Time to First Byte가 느린 이유와 대응 방법
TTFB는 하나의 버그가 아닙니다. DNS, 연결 설정, CDN 라우팅, 서버 작업, 캐시 미스, 때로는 느린 데이터베이스 쿼리 하나가 만들어 내는 눈에 보이는 지연입니다.
목차
- TTFB가 실제로 무엇을 측정하는지부터 시작하기
- 어느 정도가 느린 TTFB인가?
- 한 곳에서만 측정하지 않기
- 1. Browser developer tools
- 2. 여러 지역에서의 Synthetic tests
- 3. Real user monitoring 또는 서버 로그
- TTFB가 느린 흔한 원인
- HTML이 캐시되지 않음
- CDN이 자산만 캐시함
- 서버가 응답 전에 너무 많은 일을 함
- 데이터베이스 쿼리가 느리거나 예측 불가능함
- 애플리케이션에 cold starts가 있음
- Redirects가 첫 요청을 낭비함
- 실용적인 디버깅 순서
- Step 1: 전체 페이지가 아니라 main document를 테스트하기
- Step 2: 지역 비교하기
- Step 3: 응답 헤더 검사하기
- Step 4: origin timing 확인하기
- Step 5: 확인된 가장 큰 지연 수정하기
- 대체로 효과가 있는 수정 방법
- public HTML을 edge에서 캐시하기
- 중요하지 않은 작업을 request path 밖으로 이동하기
- 백엔드 dependency chains 줄이기
- compute를 사용자에게 더 가깝게 배치하기
- Redirects를 단순하게 유지하기
- 하지 말아야 할 것
- 계획의 차분한 버전
TTFB가 실제로 무엇을 측정하는지부터 시작하기
Time to First Byte, 보통 TTFB로 줄여 부르는 이 지표는 브라우저가 리소스를 요청한 시점부터 응답의 첫 바이트를 받을 때까지의 시간입니다.
서버 지표처럼 들리지만, 서버 지표만은 아닙니다. TTFB에는 여러 단계가 포함됩니다:
- 호스트명이 아직 확인되지 않은 경우 DNS 조회
- TCP 연결 설정
- HTTPS를 위한 TLS 협상
- 서버 또는 CDN edge까지의 요청 이동 시간
- 서버에서의 대기열 처리 및 처리 시간
- 브라우저로 돌아오는 응답 이동 시간
따라서 TTFB가 높다는 것은 백엔드가 느리다는 뜻일 수 있습니다. 동시에 사용자가 origin에서 멀리 떨어져 있거나, CDN 설정이 잘못되었거나, 캐시가 계속 미스되거나, 서버가 무엇을 보낼지 결정하는 데 너무 오래 걸린다는 뜻일 수도 있습니다.
이것이 중요한 이유는 TTFB가 로딩 체인의 초반에 있기 때문입니다. HTML 문서가 늦게 도착하면 브라우저는 CSS, JavaScript, fonts, images도 늦게 발견합니다. 프런트엔드 최적화가 훌륭하더라도 첫 문서 응답에 1.5초가 걸리면 여전히 느리게 느껴질 수 있습니다.
어느 정도가 느린 TTFB인가?
모든 사이트, 지역, 아키텍처에 맞는 보편적인 숫자는 없습니다. 그래도 실무적인 기준은 도움이 됩니다.
Google의 web.dev 가이드는 좋은 TTFB를 800 ms 미만으로 분류하며, 800–1800 ms는 개선이 필요하고 1800 ms 초과는 나쁨으로 봅니다. 사용자 가까이에서 제공되는 캐시가 잘 된 마케팅 페이지라면 이보다 훨씬 더 나은 수치도 흔히 가능합니다. 동적 작업을 수행하는 복잡한 인증된 대시보드라면 허용 가능한 수치가 더 높을 수 있지만, 여전히 설명 가능해야 합니다.
중요한 습관은 숫자를 세분화해서 보는 것입니다. 전 세계 평균 TTFB가 900 ms라고 해도, CDN edge에 가까운 사용자는 150 ms이고 다른 지역 사용자는 2200 ms일 수 있습니다. 마찬가지로 홈페이지는 괜찮지만 검색, 카테고리, 로그인 페이지는 조용히 고통스러울 수 있습니다.
한 곳에서만 측정하지 않기
단 한 번의 Lighthouse 실행만으로 TTFB를 진단하지 마세요. Lighthouse는 유용하지만, 하나의 환경에서 수행한 하나의 테스트입니다. 해석이 익숙하지 않다면 먼저 당황하지 않고 Lighthouse 보고서를 읽는 방법을 차분히 살펴보세요. 핵심은 실험실 신호와 실제 현장 현실을 분리하는 것입니다.
TTFB에는 최소한 세 가지 관점이 필요합니다:
1. Browser developer tools
Network 패널을 열고, 캐시를 비활성화한 상태로 다시 로드한 뒤, main document 요청을 확인합니다. 타이밍 분석은 DNS, connection, TLS, waiting, download 단계를 보여 줍니다. “waiting” 단계는 사람들이 흔히 백엔드 시간이라고 부르는 부분이지만, upstream latency도 포함될 수 있습니다.
2. 여러 지역에서의 Synthetic tests
사용자와 가까운 위치, 그리고 먼 위치에서 테스트를 실행합니다. 한 지역에서는 TTFB가 낮고 다른 지역에서는 높다면, 애플리케이션 코드를 다시 작성하기 전에 지리적 거리, CDN 라우팅, origin 위치, 캐시 적용 범위를 먼저 의심하세요.
3. Real user monitoring 또는 서버 로그
Field data는 실제 사용자가 다양한 기기, 네트워크, 세션에서 무엇을 경험하는지 알려 줍니다. 서버 로그는 origin이 응답을 얼마나 빨리 생성했는지 알려 줄 수 있습니다. 클라이언트가 관측한 TTFB와 origin 처리 시간의 차이에서 CDN 및 네트워크 문제가 드러나는 경우가 많습니다.
TTFB가 느린 흔한 원인
HTML이 캐시되지 않음
콘텐츠 사이트와 ecommerce 사이트에서 가장 흔한 문제입니다. 정적 자산은 적극적으로 캐시되지만, 브라우저가 가장 먼저 필요로 하는 HTML 문서는 모든 요청마다 생성됩니다.
때로는 그것이 필요합니다. 하지만 많은 경우에는 그렇지 않습니다.
공개 페이지가 하루에 몇 번만 바뀐다면, 익명 방문자마다 새 데이터베이스 렌더링을 요구해서는 안 될 가능성이 큽니다. 상황에 맞게 full-page caching, edge caching, static generation, stale-while-revalidate 패턴을 사용하세요.
응답 헤더에서 Cache-Control, CDN-Cache-Status, Age, Vary, Set-Cookie 같은 신호를 확인하세요. 모든 방문자에게 고유 쿠키를 보내는 페이지는 실수로 스스로를 캐시 불가능하게 만들 수 있습니다. 이 계층을 실무적으로 판단하는 방법이 필요하다면, 프로덕션에서 redirects와 HTTP headers를 디버깅하는 작은 도구 모음에 대한 가이드의 같은 디버깅 습관이 TTFB 작업에도 그대로 적용됩니다.
CDN이 자산만 캐시함
많은 팀이 CDN을 추가하고 성능 작업이 끝났다고 생각합니다. 하지만 CDN이 images, CSS, JavaScript만 제공한다면 첫 HTML 요청은 여전히 단일 origin server까지 끝까지 이동할 수 있습니다.
지역 사용자가 있는 로컬 비즈니스 사이트라면 괜찮을 수 있습니다. 국제적인 audience에는 괜찮지 않습니다. 사용자가 origin에서 멀수록 백엔드 작업이 시작되기도 전에 더 많은 latency를 지불하게 됩니다.
TTFB를 위한 좋은 CDN 설정은 대개 다음을 의미합니다:
- 안전한 경우 public HTML 캐시
- 인증되었거나 개인화된 페이지에 대한 의도적인 bypass 규칙 준수
- 캐시를 지나치게 잘게 쪼개는 불필요한
Vary헤더 피하기 - 캐시를 완전히 비활성화하는 대신 cache purging 또는 revalidation 사용
- edge locations가 모든 요청을 전달하는 것이 아니라 실제로 hit를 제공하는지 확인
CDN은 마법이 아닙니다. 캐시이자 라우팅 계층입니다. 그렇게 다루세요.
서버가 응답 전에 너무 많은 일을 함
느린 백엔드 경로는 여러 작은 지연에서 비롯될 수 있습니다: 데이터베이스 쿼리, API 호출, 템플릿 렌더링, feature flag 확인, 인증, 개인화, 로깅, cold starts.
가장 나쁜 패턴은 직렬 의존 작업입니다. 예를 들면:
- 페이지 데이터 가져오기
- 그다음 관련 상품 가져오기
- 그다음 가격 가져오기
- 그다음 recommendations service 호출하기
- 그다음 HTML 렌더링하기
각 단계가 이전 단계를 기다리면 TTFB는 빠르게 증가합니다. 독립적인 작업은 병렬화하고, 첫 응답에 중요하지 않은 호출은 제거하며, 비용이 큰 결과는 캐시하세요.
유용한 규칙 하나: 사용자가 그 결과를 즉시 보거나 사용할 수 없다면, 첫 바이트를 막아서는 안 될 가능성이 큽니다.
데이터베이스 쿼리가 느리거나 예측 불가능함
데이터베이스는 개발 환경에서는 잘 동작하다가 실제 트래픽에서는 나쁘게 동작하는 경우가 많아 TTFB 문제를 일으키곤 합니다. 누락된 인덱스, 큰 조인, N+1 쿼리, lock contention, 과도하게 큰 result sets는 모두 “서버가 느리다”로 나타납니다.
여기서는 추측하지 마세요. 느린 요청의 쿼리 시간을 수집하세요. 평균만 보지 말고 p95와 p99를 보세요. 어떤 페이지가 보통 120 ms에 응답하더라도 가끔 4초 동안 막힌다면 여전히 나쁜 사용자 경험을 만듭니다.
일반적인 수정 방법은 다음과 같습니다:
- 인덱스 추가 또는 수정
- N+1 쿼리 패턴 제거
- 읽기 중심 데이터 캐싱
- 큰 쿼리 페이지네이션
- reporting 또는 analytics 쿼리를 request time에서 분리
- downstream calls에 합리적인 timeouts 설정
애플리케이션에 cold starts가 있음
Serverless 및 containerized platforms는 훌륭할 수 있지만, 트래픽이 bursty하거나 region이 under-provisioned된 경우 cold starts가 TTFB를 해칠 수 있습니다.
유휴 시간 이후의 첫 요청이 이후 요청보다 훨씬 느리다면 cold starts를 조사하세요. provisioned concurrency, 더 작은 bundles, 더 적은 startup dependencies, warmer functions, 또는 latency-sensitive routes를 위한 다른 배포 형태가 필요할 수 있습니다.
이것은 serverless에 반대하는 주장이 아닙니다. runtime model이 보이지 않는다고 가장하는 것에 반대하는 주장입니다.
Redirects가 첫 요청을 낭비함
Redirect는 브라우저가 최종 문서를 받기 전에 또 한 번의 request-response cycle을 추가합니다. 오래된 링크 때문에 http://에서 https://로 한 번 redirect하는 것은 피할 수 없을 수 있지만, chains는 낭비입니다.
흔한 chains는 다음과 같습니다:
http://example.com→https://example.com→https://www.example.com- protocol normalization 이후 trailing slash normalization
- cache lookup 이전 geo 또는 language redirects
- 여러 URLs를 거쳐 이동하는 오래된 campaign links
가능한 경우 원본 링크를 수정하고, redirect rules를 합치며, canonical URLs가 직접 연결되게 하세요. Redirect 시간은 최종 요청의 TTFB로 항상 보고되지는 않지만, 사용자는 여전히 그 비용을 지불합니다.
실용적인 디버깅 순서
TTFB가 느려 보일 때는 이 순서를 사용하세요. 캐시와 라우팅 동작을 확인하기 전에 애플리케이션 코드를 최적화하는 흔한 실수를 피할 수 있습니다.
Step 1: 전체 페이지가 아니라 main document를 테스트하기
HTML document 요청을 찾습니다. 전체 TTFB와 timing breakdown을 기록합니다. 브라우저 캐시를 켠 경우와 끈 경우 모두 반복합니다. 관련이 있다면 public page, dynamic page, logged-in page를 테스트합니다.
Step 2: 지역 비교하기
동일한 URL을 여러 지리적 위치에서 실행합니다. 느린 지역이 origin과의 거리와 상관관계를 보인다면 CDN과 edge caching을 우선하세요. 모든 지역이 느리다면 backend processing과 origin capacity를 살펴보세요.
Step 3: 응답 헤더 검사하기
cache headers, cookies, Age, CDN status, Vary를 확인합니다. 누락된 Age 헤더나 반복되는 cache misses는 단서입니다. public HTML의 광범위한 Vary: Cookie 헤더는 흔히 캐시를 망치는 원인입니다.
Step 4: origin timing 확인하기
서버 타이밍 계측을 추가합니다. Server-Timing 헤더는 database time, render time, upstream API time 같은 백엔드 단계를 노출할 수 있습니다. 단순한 labels만으로도 유용합니다:
Server-Timing: db;dur=82, render;dur=41, api;dur=210
이제 브라우저 타이밍은 서버가 실제 작업에 300 ms를 썼는지, 아니면 요청이 애플리케이션에 도달하기 전에 지연이 발생했는지를 보여 줄 수 있습니다.
Step 5: 확인된 가장 큰 지연 수정하기
당연하게 들리지만, 팀들은 측정된 것보다 익숙한 것을 고치는 경우가 많습니다. cache misses가 지배적이면 caching을 고치세요. 데이터베이스가 지배적이면 쿼리를 고치세요. 전 세계 사용자의 TLS와 connection setup이 지배적이면 routing, CDN coverage, origin geography를 고치세요.
프런트엔드 작업도 여전히 중요합니다. Fonts, images, JavaScript는 HTML이 도착한 뒤에 일어나는 일에 영향을 줍니다. 하지만 빠른 첫 응답의 대체재는 아닙니다. 렌더 성능도 함께 개선하고 있다면, web fonts는 많은 사이트에서 여전히 가장 쉬운 성능 개선 포인트 중 하나입니다. 문서가 도착한 뒤 텍스트가 얼마나 빨리 사용 가능해지는지에 영향을 주기 때문입니다.
대체로 효과가 있는 수정 방법
public HTML을 edge에서 캐시하기
마케팅 페이지, 문서, 블로그, 랜딩 페이지, 카테고리 페이지에서는 edge caching이 TTFB를 가장 크게 개선하는 경우가 많습니다. 콘텐츠가 자주 바뀐다면 짧은 TTLs를 사용하세요. 캐시가 백그라운드에서 갱신되는 동안 약간 오래된 콘텐츠가 허용된다면 stale-while-revalidate를 사용하세요.
개인화에는 주의하세요. 페이지가 currency, language, login state, experiment group에 따라 달라진다면 해당 variants를 명시적으로 정의하세요. 의도치 않은 사용자별 variation은 캐시 효율을 무너뜨립니다.
중요하지 않은 작업을 request path 밖으로 이동하기
Email sending, analytics enrichment, recommendation generation, webhook calls, heavy logging은 첫 바이트를 막는 경우가 거의 없어야 합니다. 큐에 넣거나 응답이 시작된 뒤 실행하세요.
백엔드 dependency chains 줄이기
독립적인 호출은 병렬화하세요. 느린 API 응답은 캐시하세요. timeouts를 설정하세요. 도움이 되지만 필수는 아닌 서비스에는 fallback content를 설계하세요.
느린 recommendations widget이 전체 상품 페이지를 지연시켜서는 안 됩니다.
compute를 사용자에게 더 가깝게 배치하기
사용자가 전 세계에 있고 origin이 한 지역에 있다면 latency는 구조적인 문제입니다. CDN caching은 public content에 대해 이 문제의 상당 부분을 숨길 수 있습니다. dynamic content의 경우 regional deployments, 적합한 routes에 대한 edge rendering, 또는 audience에 더 가까운 APIs 이동을 고려하세요.
Redirects를 단순하게 유지하기
URLs를 한 번의 hop으로 canonicalize하세요. 사용자와 crawlers가 최종 목적지로 직접 가도록 internal links를 업데이트하세요. 오래된 campaign URLs와 platform migrations를 감사하세요. Redirects는 잘 작동할 때 보이지 않기 때문에 무시하기 쉽지만, 여전히 시간이 듭니다.
하지 말아야 할 것
모든 route에 완벽한 TTFB 숫자를 좇지 마세요. 실제 계산을 수행하는 인증된 report는 캐시된 blog post처럼 동작하지 않습니다.
average TTFB를 유일한 지표로 사용하지 마세요. Percentiles가 중요합니다. Geography가 중요합니다. Page type이 중요합니다.
CDN이 있다고 해서 HTML이 캐시된다고 가정하지 마세요. 확인하세요.
그리고 TTFB를 제품 결정과 분리해서 다루지 마세요. Personalization, experimentation, real-time inventory, third-party services는 모두 latency 비용을 갖습니다. 어떤 것은 그만한 가치가 있습니다. 어떤 것은 단지 습관일 뿐입니다.
<!-- tool-cta:start -->
💡 시도해 보세요: TTFB를 진단할 때, Get Headers는 캐시 상태, 서버 타이밍 및 리디렉션을 보여 주어 지연이 어디에서 발생하는지 설명해 주는 경우가 많습니다.
<!-- tool-cta:end -->
계획의 차분한 버전
느린 TTFB는 모호한 “서버 문제”로 다루는 것을 멈추면 대개 고칠 수 있습니다. 문서 요청을 측정하세요. 지역과 페이지 유형별로 세분화하세요. 헤더를 검사하세요. 클라이언트 타이밍과 origin 타이밍을 비교하세요. 그런 다음 확인된 가장 큰 병목을 수정하세요.
대부분의 사이트에는 이국적인 아키텍처가 필요하지 않습니다. 피할 수 있는 cache misses를 줄이고, blocking backend work를 줄이며, redirects를 더 깔끔하게 만들고, 첫 바이트가 전송되기 전에 반드시 일어나야 하는 일이 무엇인지 더 명확히 이해하면 됩니다.