웹 인프라

정적 사이트 생성(SSG), 미리 차려 두는 웹

방문자가 오기 전에 페이지를 만들면 어떤 일이 달라질까요? 정적 사이트와 캐시의 차이, 미리 만들어도 되는 화면의 조건을 알아봐요.

이 글의 목차캐시와는 다른 이야기다5
  1. 캐시와는 다른 이야기다
  2. 서버가 매번 조립하던 시절
  3. 미리 굽기로 한 사람들
  4. 지금은 화면 단위로 고른다
  5. 저는 이 블로그를 어떻게 정했나

동네 도시락 가게 두 곳을 떠올려 보세요. 한 곳은 주문을 받은 뒤에 쌀을 안치고, 다른 한 곳은 아침에 미리 만들어 진열대에 올려 둬요. 평소에는 비슷해 보이지만 점심시간에 백 명이 몰리면 앞의 가게에서는 주방 앞에 줄이 서고 뒤의 가게에서는 계산대만 붐벼요. 병목의 위치가 달라요.

웹에서 이 갈림길은 한 가지 질문으로 좁혀져요. 브라우저가 받아 갈 HTML 문서를 언제 만들 것인가. 요청이 들어온 뒤에 조립하면 동적 방식이고, 요청이 들어오기 전에 만들어 파일로 저장해 두면 정적 방식이에요. 미리 만드는 그 한 번의 작업을 빌드(build)라고 부르고, 사이트의 모든 화면을 빌드 한 번으로 구워 두는 방식에 정적 사이트 생성, 줄여서 SSG라는 이름이 붙었어요.

생성 시점에 따른 HTML 응답 경로 동적 경로는 요청마다 데이터 조회와 조립을 통과하지만, 정적 경로는 빌드에서 만든 파일만 읽어 응답한다. 개념 도해 생성 시점에 따른 HTML 응답 경로 HTML 생성 경로 요청 때 생성 ① 방문 ② 데이터 조회 ③ HTML 조립 ④ 응답 요청마다 반복 미리 생성 ① 콘텐츠 저장 ② 빌드 ③ 완성 파일 ④ 방문·응답 파일 읽기 방문 시점 전후의 생성 작업 방문 시점 동적 경로 데이터 조회 · HTML 조립 응답 전 작업 정적 경로 빌드 · 완성 파일 저장 완성 파일 반환 요청 이전 요청 이후 · 시간 동적 경로는 요청마다 데이터 조회와 조립을 통과하지만, 정적 경로는 빌드에서 만든 파일만 읽어 응답한다. SOSHIN · DEV NOTES
같은 화면이라도 만드는 시점이 방문 순간인지 그 이전인지에 따라 거쳐야 할 단계가 달라져요.

캐시와는 다른 이야기다

여기서 캐시와 헷갈릴 수 있어요. 캐시는 이미 계산한 결과를 다음 요청에 다시 쓰는 방법이에요. 첫 요청 때 채울 수도 있고 미리 채워 둘 수도 있죠. 정적 사이트 생성은 페이지를 만드는 시점을 배포 전으로 옮기는 방법이에요. 역할이 달라서 함께 쓸 수 있어요. 미리 만든 HTML 파일을 CDN에 캐시하는 이 블로그도 그런 경우예요.

차이는 데이터가 언제 확정되는가로도 볼 수 있어요. 정적 방식은 빌드 시점의 데이터로 화면을 굳혀요. 그래서 빌드 이후에 바뀐 내용은 다시 굽기 전까지 반영되지 않아요. 이것이 정적 방식의 진짜 제약이고, 속도나 기술 수준의 문제가 아니라 신선도를 얼마나 포기할 수 있느냐의 문제예요.

서버가 매번 조립하던 시절

초기 웹 서버가 하는 일은 디스크에 있는 파일을 그대로 돌려주는 것뿐이었어요. 방문자마다 다른 화면을 주려면 서버가 외부 프로그램을 실행하고 그 출력을 응답으로 넘길 방법이 필요했어요. 그 규약이 CGI(Common Gateway Interface)이고, 1993년부터 웹에서 쓰였으며 훗날 RFC 3875로 정리됐어요.

이 규약 위에서 개인이 만든 도구가 시대를 바꾸기도 했어요. 1994년 Rasmus Lerdorf는 자기 온라인 이력서의 방문자를 세려고 C로 짠 CGI 프로그램 묶음을 만들었고, 1995년 6월 그 코드를 공개했어요. 오늘날의 PHP가 여기서 출발해요. 2003년 5월에는 Matt Mullenweg가 WordPress의 첫 배포를 알렸어요. 업데이트가 멈춘 b2/cafelog의 공개 코드를 이어받은 것이었고 Mike Little이 함께했어요.

이 구조가 치르는 대가는 분명해요. 읽는 사람이 늘수록 같은 계산이 그만큼 반복되므로 트래픽과 계산량이 함께 늘어요. 그리고 그 계산을 맡은 서버나 데이터베이스가 멈추면 이미 완성돼 있던 어제의 글까지 함께 보이지 않아요. 읽기만 하는 방문자가 쓰기용 인프라의 가용성에 묶여 있는 셈이에요.

미리 굽기로 한 사람들

2008년 11월 17일 Tom Preston-Werner는 자기 블로그를 데이터베이스 없이 운영하겠다고 선언했어요. 글은 텍스트 파일로 쓰고, 도구가 그 파일들을 읽어 완성된 HTML 묶음을 만들고, 서버는 그것을 그대로 내보내요. 그가 만든 도구가 Jekyll이었어요.

생성 시점에 따른 누적 작업량 정적 생성은 만드는 비용을 저장 시점에 치르고 이후 방문 수와 분리한다. 개념 도해 생성 시점에 따른 누적 작업량 콘텐츠 생성 경로 방문 때 생성 ① 방문 ② 화면 조립 ③ 응답 방문마다 반복 저장 때 생성 ① 글 저장 ② 빌드 ③ 완성 파일 방문들 · 파일 읽기 누적 생성 작업 누적 작업량 방문 증가 저장 시 1회 기준 저장 때 생성 방문 때 생성 저장 첫 방문 정적 생성은 만드는 비용을 저장 시점에 치르고 이후 방문 수와 분리한다. SOSHIN · DEV NOTES
만드는 일은 글을 저장할 때 한 번으로 끝나고, 그 뒤의 방문은 이미 끝난 결과를 읽는 일이 돼요.

발상 자체는 웹의 첫 모습으로 돌아간 쪽에 가까워요. 달라진 것은 사람이 HTML을 손으로 쓰지 않아도 된다는 점이에요. 계산의 위치가 요청 처리에서 배포 준비로 옮겨 가면서 방문자 수와 계산량이 분리됐어요. 2015년 11월 Netlify의 Mathias Biilmann과 Chris Bach는 이 흐름에 Jamstack이라는 이름을 붙였어요. 화면을 보여 줄 때마다 사이트를 만들어 내는 백엔드를 직접 운영하지 않아도 된다는 설명이었어요.

지금은 화면 단위로 고른다

정적 방식이 잘 맞는지 보려면 화면 하나를 떠올려 보세요. 이 결과를 모든 방문자에게 똑같이 줘도 될까요? 글 본문은 대개 그렇지만, 내 주문 내역은 그렇지 않겠죠. 무엇을 언제 확정할 수 있는지가 선택을 나눠요.

화면의 성격잘 맞는 방식그 방식이 실패하면
누가 봐도 같은 글과 문서미리 굽는다빌드가 깨져 새 내용이 안 올라간다
로그인한 사람마다 다른 장바구니요청 때 조립한다서버가 멈추면 화면이 안 뜬다
대부분 같고 일부만 다른 화면뼈대만 굽고 나머지는 채운다채우는 쪽만 비어 화면 일부가 빈다

세 번째 줄이 요즘의 기본에 가까워요. 목록과 본문처럼 모두에게 같은 부분은 미리 굽고, 로그인 상태나 실시간 수치처럼 사람마다 다른 조각만 방문 이후에 채워요. 예전에는 사이트 전체를 하나로 정해야 했지만 지금은 경계를 화면 안쪽까지 그을 수 있어요.

저는 이 블로그를 어떻게 정했나

이 블로그의 글은 누가 읽어도 같고, 하루에 몇 번씩 바뀌지도 않아요. 신선도를 포기해도 잃을 것이 거의 없는 조건이라 정적 쪽을 골랐어요.

정하고 나서 체감한 이득은 배포가 실패해도 기존 글이 남는다는 점이었어요. 글을 다시 만드는 단계가 성공해야 새 파일을 공개하도록 두었거든요. 이 안전망은 정적 사이트라는 이름만으로 생기지는 않아요. 실패한 배포가 기존 파일을 덮어쓰지 않도록 배포 방식도 맞아야 해요. 동적 서비스에서도 사전 검사와 배포 전환으로 비슷한 보호를 만들 수 있고요.

새벽에 서버가 살아 있는지 확인할 일이 없어진 것도 결국 같은 이야기였어요. 읽기 경로에서 계산을 걷어내면 그 경로에서 고장 날 것도 함께 줄어들어요.

소신을 상징하는 까마귀 목판화 일러스트
작성자소신 · Soshin

웹과 서버를 만들고, 개발하며 배운 것들을 글로 남깁니다.

좌우로 움직여 보세요