Time to First Byte (TTFB) 문제 식별 및 수정
RUM 데이터, Server-Timing 헤더 및 체계적인 TTFB 하위 부분 분석을 사용하여 페이지의 Time to First Byte 문제를 디버깅하는 방법을 알아보세요.

Time to First Byte (TTFB) 문제 찾기 및 수정
이 문서는 Time to First Byte (TTFB) 가이드의 일부입니다. TTFB는 사용자가 페이지를 요청한 후 브라우저가 응답의 첫 번째 바이트를 수신할 때까지의 시간을 측정하는 진단 지표입니다. TTFB 자체가 Core Web Vitals는 아니지만 First Contentful Paint (FCP) 및 Largest Contentful Paint (LCP) 모두에 직접적인 영향을 미칩니다. 좋은 TTFB는 75번째 백분위수에서 800밀리초 미만입니다.
이전 기사에서는 Time to First Byte에 대해 이야기했습니다. 기본 사항을 읽어보고 싶다면 훌륭한 시작점이 될 것입니다.
이 문서에서는 다양한 Time to First Byte 문제를 식별하는 데 중점을 두고 이를 수정하는 방법을 설명합니다.
TTFB 팁: 대부분의 경우 처음 방문하는 사용자는 사이트의 DNS 캐시가 없기 때문에 TTFB가 훨씬 더 나쁩니다. TTFB를 추적할 때 처음 방문자와 재방문자를 구분하는 것이 매우 중요합니다.
Table of Contents!
1단계: Search Console에서 TTFB 확인
"회복을 위한 첫 번째 단계는 문제가 있음을 인정하는 것입니다." 따라서 Time to First Byte를 수정하기 전에 실제로 TTFB에 문제가 있는지 확인해 보겠습니다.
안타깝게도 Time to First Byte는 Google Search Console에 보고되지 않으므로 사이트의 CrUX 데이터를 쿼리하려면 pagespeed.web.dev를 사용해야 합니다. 다행히 단계는 간단합니다. pagespeed.web.dev로 이동하여 페이지의 URL을 입력하고 "origin" 버튼이 선택되어 있는지 확인합니다(홈페이지 데이터뿐만 아니라 사이트 전체 데이터가 필요하기 때문입니다). 이제 모바일과 데스크톱 간에 전환하여 두 기기 유형 모두의 Time to First Byte를 확인하세요.
아래 예시에서는 높은 TTFB로 인해 Core Web Vitals를 통과하지 못하는 사이트를 볼 수 있습니다.

1b단계: 더 깊은 통찰력을 얻기 위해 Server-Timing 헤더 사용
Server-Timing HTTP 응답 헤더를 사용하면 서버가 백엔드 성능 지표를 브라우저에 직접 전달할 수 있습니다. 이를 통해 서버 로그에 액세스할 필요 없이 서버 처리의 어느 부분이 느린지 정확하게 찾아낼 수 있습니다.
일반적인 Server-Timing 헤더는 다음과 같습니다.
Server-Timing: db;dur=53, app;dur=120, cache;desc="miss"
이 예시에서 서버는 세 가지 타이밍 값을 보고합니다.
- db;dur=53: 데이터베이스 쿼리에 53밀리초가 걸렸습니다.
- app;dur=120: 애플리케이션 로직(템플릿 렌더링, API 호출 등)에 120밀리초가 걸렸습니다.
- cache;desc="miss": 이 요청에 서버 캐시가 사용되지 않았습니다(캐시 미스).
Chrome DevTools에서 네트워크 탭을 열고 문서 요청을 선택한 다음 타이밍 탭의 "Server Timing" 섹션으로 스크롤하여 이러한 값을 읽을 수 있습니다. 이 값은 JavaScript의 PerformanceServerTiming API를 통해서도 액세스할 수 있습니다.
const [navigation] = performance.getEntriesByType('navigation');
if (navigation.serverTiming) {
navigation.serverTiming.forEach(entry => {
console.log(`${entry.name}: ${entry.duration}ms (${entry.description})`);
});
} 서버가 아직 Server-Timing 헤더를 보내지 않는다면 추가하는 것을 고려해 보세요. 대부분의 웹 프레임워크는 이를 간단하게 만듭니다. PHP에서는 출력이 있기 전에 헤더를 추가할 수 있습니다.
header('Server-Timing: db;dur=' . $dbTime . ', app;dur=' . $appTime); Express를 사용하는 Node.js의 경우:
res.setHeader('Server-Timing', `db;dur=${dbTime}, app;dur=${appTime}`); Server-Timing 헤더는 실제 사용자가 경험하는 TTFB와 서버 측 성능을 연관시킬 수 있기 때문에 RUM(Real User Monitoring)과 결합할 때 특히 유용합니다. 전체 응답이 준비되기 전에 리소스 힌트를 전송하여 체감되는 TTFB를 추가로 줄이는 방법에 대해 103 Early Hints에서 자세히 알아보세요.
2단계: RUM 추적 설정
Time to First Byte는 까다로운 지표입니다. 실제 환경에서는 다른 요인들이 TTFB의 변동성에 기여하기 때문에 단순히 합성 테스트(synthetic test)에 의존하여 TTFB를 측정할 수 없습니다. 위의 모든 질문에 대한 답을 얻으려면 실제 데이터를 측정하고 Time to First Byte에서 발생할 수 있는 모든 문제를 기록해야 합니다. 이를 Real User Monitoring(RUM)이라고 하며 RUM 추적을 활성화하는 방법에는 여러 가지가 있습니다. 우리는 이러한 사용 사례를 위해 특별히 CoreDash를 개발했습니다. CoreDash는 저비용으로 빠르고 효과적인 RUM 도구로서 제 역할을 다합니다. 물론 시중에는 많은 RUM 솔루션이 있으며 이들도 (비록 가격은 더 비싸지만) 제 역할을 할 것입니다.

TTFB에 대한 생각: 웹 서버를 식당 주방이라고 생각하고, 웹페이지를 요청하는 사용자를 주문을 하는 배고픈 손님이라고 상상해 보세요. Time to First Byte (TTFB)는 고객이 주문을 한 시점부터 주방에서 음식을 준비하기 시작할 때까지의 시간입니다.
따라서 TTFB는 전체 식사가 얼마나 빨리 조리되고(First Contentful Paint) 제공되는지 (Largest Contentful Paint)에 대한 것이 아니라 주방이 초기 요청에 얼마나 반응하는지에 대한 것입니다.
RUM 추적은 고객의 식사 경험을 이해하기 위해 설문조사하는 것과 같습니다. 주방에서 더 멀리 앉은 고객은 웨이터의 주의를 덜 받아 나중에 서빙을 받거나, 단골 고객은 우대 대우를 받는 반면 새로운 방문자는 자리를 위해 더 오래 기다려야 한다는 것을 알 수 있습니다.
2b단계: 성능 베이스라인 설정
변경을 수행하기 전에 TTFB의 베이스라인을 설정하세요. 나중에 최적화의 효과를 측정하는 데 도움이 되므로 다음 측정 기준에 걸쳐 75번째 백분위수 TTFB를 기록합니다.
- 전체 TTFB(모바일 및 데스크톱 별도): 각 기기 유형에 대한 75번째 백분위수를 캡처합니다.
- 트래픽 기준 상위 10개 페이지: 트래픽이 가장 많은 페이지의 TTFB를 개별적으로 기록합니다.
- 신규 방문자 대 재방문자: 처음 방문하는 사람은 일반적으로 DNS 및 연결 오버헤드로 인해 TTFB가 더 높습니다.
- 트래픽 기준 상위 5개국: 서버와의 지리적 거리는 TTFB에 큰 영향을 미칩니다.
- TTFB 하위 부분 분류: 각 하위 부분(waiting, cache, DNS, connection, request)에 대한 75번째 백분위수를 기록합니다.
이 수치를 스프레드시트에 문서화하세요. 각 최적화를 구현한 후 결과를 비교하기 전에 충분한 RUM 데이터를 수집하기 위해 최소 7일을 기다리십시오. 좋은 접근 방식은 한 번에 하나의 TTFB 하위 부분을 해결하고 측정하고 다음으로 넘어가는 것입니다.
3단계: Time to First Byte 문제 식별
Google의 Chrome 사용자 경험 보고서(CrUX)는 귀중한 필드 데이터를 제공하지만 높은 TTFB의 원인에 대한 구체적인 세부 정보는 제공하지 않습니다. TTFB를 효과적으로 개선하려면 보다 자세한 수준에서 정확히 무슨 일이 일어나고 있는지 알아야 합니다. 이 시점에서 전체적으로 실패하는 TTFB와 특정 조건 하에서 실패하는 TTFB를 구별하는 것이 이치에 맞습니다(현실에서는 항상 혼합되어 나타나겠지만).
3.1 전체적으로 TTFB가 실패하는 경우
- 일반적으로 불량한 "요청 시간" 확인: 요청 시간이 불량하다는 것은 "문제"가 서버가 페이지를 생성하는 데 걸리는 시간에 있음을 의미합니다. 이는 좋지 않은 TTFB 점수의 가장 일반적인 원인입니다.
- 다른 불량한 TTFB 하위 부분 확인: TTFB는 단일 지표가 아니라 각각 자체적인 최적화 잠재력을 가진 여러 부분으로 나눌 수 있습니다. waiting duration, cache duration, DNS 조회 기간 또는 connection duration이 느린 경우 서버 설정을 조정하거나 더 나은 품질의 호스팅을 찾기 시작해야 할 수 있습니다.

3.2 특정 조건에서 TTFB가 실패하는 경우
- 국가 세분화: 높은 TTFB의 지리적 분포를 이해하는 것은 특히 전 세계 고객을 대상으로 하는 웹사이트에 중요합니다. 한 국가의 단일 서버에서만 페이지를 제공하는 경우(CDN 엣지 캐싱 없이) 사용자의 위치와 웹사이트를 호스팅하는 서버 간의 물리적 거리로 인해 모든 종류의 지연이 발생하고 TTFB에 영향을 미칩니다. 콘텐츠를 전 세계 사용자에게 더 가깝게 제공하기 위해 Cloudflare 구성 또는 다른 CDN을 고려해 보세요.

- 캐시 세분화: 캐싱은 서버 측의 HTML 생성을 건너뛰어 TTFB를 줄일 수 있습니다. 불행히도 캐싱이 여러 가지 이유로 비활성화되거나 우회되는 것이 일반적입니다. 예를 들어 로그인한 사용자, 장바구니 페이지, 쿼리 문자열이 있는 페이지(예: Google Ads에서 유입), 검색 결과 페이지, 결제 페이지에 대해 캐싱이 비활성화될 수 있습니다. 웹사이트에서 (엣지) 캐싱을 사용하는 경우 RUM 추적을 사용하여 캐시 적중률을 확인하세요.

- 페이지(클러스터) 세분화: 페이지 또는 페이지 유형 간의 Time to First Byte 성능 차이(또는 차이 부족)도 우리가 결정해야 할 또 다른 사항입니다. 어떤 페이지가 TTFB 지표를 충족하지 못하는지 알면 Time to First Byte를 개선하는 방법에 대한 귀중한 통찰력을 얻을 수 있습니다.

- 리디렉션 세분화: 리디렉션 시간은 TTFB에 직접 추가됩니다. 각 리디렉션은 웹 서버가 페이지 로딩을 시작하기 전에 추가 시간을 더합니다. 불필요한 리디렉션을 측정하고 제거하면 TTFB를 개선하는 데 도움이 될 수 있습니다. 리디렉션 최적화에 대한 자세한 내용은 TTFB의 대기 기간 하위 부분에 대한 가이드를 참조하세요.

- 기타 세분화: 위의 변수로 세분화하면 일반적인 의심 대상을 포괄하지만, 모든 사이트는 고유하며 각자의 과제를 가지고 있습니다. 다행히도 RUM 추적은 장치 RAM, 네트워크 속도, 장치 유형, 운영 체제, 사용자 지정 변수 및 훨씬 더 많은 변수에 의한 세분화를 허용하도록 설계되었습니다.
4단계: 문제를 자세히 살펴보고 수정하기

Time to First Byte (TTFB)의 하위 부분은 다음과 같습니다.
5단계: 일반적인 TTFB 문제에 대한 빠른 수정 체크리스트
TTFB에 가장 큰 영향을 미치는 하위 부분을 기준으로 한 가장 일반적인 수정 사항에 대한 빠른 참조입니다.
| TTFB 하위 부분 | 가장 일반적인 원인 | 빠른 수정 |
|---|---|---|
| 대기 기간 | 불필요한 리디렉션 | 리디렉션 체인 감사 및 제거; HSTS 구현 |
| 캐시 기간 | 느린 서비스 워커 부팅 | 서비스 워커 코드 간소화; 효율적인 캐싱 전략 사용 |
| DNS 기간 | 느린 DNS 공급자 | Cloudflare와 같은 프리미엄 DNS 공급자로 전환; TTL 설정 조정 |
| 연결 기간 | 구식 TLS 버전 | TLS 1.3 및 HTTP/3 활성화; 근접성을 위해 CDN 사용 |
| 요청 기간 | 느린 서버 처리 | 서버 측 캐싱 구현; 데이터베이스 쿼리 최적화; 103 Early Hints 사용 |
JavaScript로 TTFB 측정하기
Navigation Timing API를 사용하여 브라우저에서 직접 전체 TTFB와 해당 하위 부분을 측정할 수 있습니다. 다음 스니펫은 TTFB를 계산하고 각 하위 부분을 기록합니다.
new PerformanceObserver((entryList) => {
const [nav] = entryList.getEntriesByType('navigation');
const activationStart = nav.activationStart || 0;
const ttfb = nav.responseStart - activationStart;
const waitingDuration = (nav.workerStart || nav.fetchStart) - activationStart;
const cacheDuration = nav.domainLookupStart - (nav.workerStart || nav.fetchStart);
const dnsDuration = nav.domainLookupEnd - nav.domainLookupStart;
const connectionDuration = nav.connectEnd - nav.connectStart;
const requestDuration = nav.responseStart - nav.requestStart;
console.log('TTFB:', ttfb.toFixed(0), 'ms');
console.log(' Waiting:', waitingDuration.toFixed(0), 'ms');
console.log(' Cache:', cacheDuration.toFixed(0), 'ms');
console.log(' DNS:', dnsDuration.toFixed(0), 'ms');
console.log(' Connection:', connectionDuration.toFixed(0), 'ms');
console.log(' Request:', requestDuration.toFixed(0), 'ms');
}).observe({
type: 'navigation',
buffered: true
}); 이 코드는 CoreDash와 같은 도구가 TTFB 기여도(attribution) 패널에 표시하는 것과 동일한 분석을 제공합니다. 브라우저 콘솔에서 이 스니펫을 실행하면 단일 페이지 로드에 대한 즉각적인 수치를 얻을 수 있는 반면, RUM 도구는 수천 명의 실제 사용자를 대상으로 이 데이터를 수집하여 신뢰할 수 있는 75번째 백분위수 값을 생성합니다.
추가 읽을거리: 최적화 가이드
관련 가이드:
- 103 Early Hints: 전체 응답이 준비되기 전에 리소스 힌트를 전송하여 서버가 계속 처리하는 동안 브라우저가 중요한 리소스 로드를 시작할 수 있도록 합니다.
- 성능을 위한 Cloudflare 구성: Cloudflare의 CDN, 캐싱 및 엣지 기능을 설정하여 전 세계 사용자를 위한 TTFB를 줄입니다.
TTFB 하위 부분: 전체 가이드
Time to First Byte의 각 하위 부분에는 자체적인 최적화 전략이 있습니다. RUM 데이터에서 병목 현상으로 식별되는 하위 부분부터 시작하세요.

