같은 서버, 같은 네트워크라도 압축 설정만 잘해도 전송 바이트와 TTFB·LCP가 눈에 띄게 내려갑니다. 대표 코덱은 Brotli와 Gzip. 무엇을 어디에, 어느 수준으로 적용할지가 핵심입니다. 이 글은 텍스트/이미지/폰트별 최적 선택, 정적·동적 전송 전략, 레벨 튜닝을 한 번에 정리합니다.
1) 코덱 한눈에 보기
- Gzip: 가장 널리 호환. 압축·해제 모두 빠르고 CPU 부담이 낮음.
- Brotli: 텍스트(HTML/CSS/JS)에서 더 높은 압축 효율. 고레벨에서 특히 유리하나 인코딩 CPU가 상대적으로 큼.
- 원칙: 정적 파일(캐시 가능) 은 Brotli 고레벨 선압축, 동적 응답은 CPU 여유에 맞춰 Gzip 또는 Brotli 중간 레벨.
2) 텍스트 리소스별 추천안
HTML
- 권장: Brotli 레벨 9–11(정적/사전압축), 동적 페이지는 레벨 5–7 또는 Gzip 레벨 6–7.
- 효과: 초기 페인트/TTFB에 직접적 이득. 템플릿 캐싱이 있다면 Brotli 유지가 유리.
CSS/JS
- 권장: 빌드 단계에서 Brotli(브로틀리) 사전압축 파일을 함께 배포(.br, .gz).
- 주의: 번들러가 이미 최적화(난독화/트리셰이킹)했다면 Brotli 이득↑.
- 운영: CDN/웹서버에서 콘텐츠 협상으로 브라우저가 .br 우선 수신.
JSON/텍스트 API
- 권장: 트래픽이 크고 캐시 가능하면 Brotli 5–7, 실시간 API는 Gzip 6으로 지연·CPU 균형.
- 팁: 중복 키를 줄이는 JSON 미니파이가 선행되면 압축 효율 상승.
3) 이미지 리소스: 언제 압축을 꺼야 하나
- JPEG/PNG/WebP/AVIF: 추가로 Gzip/Brotli를 적용하지 않습니다. 이미 자체 압축 포맷이며 재압축 이득이 거의 없고 CPU만 낭비합니다.
- SVG(텍스트 기반): 압축 권장. Brotli 레벨 9–11로 용량이 크게 줄어듭니다.
- 아이콘·일러스트: 가능하면 SVG 우선. 비트맵이라면 포맷 최적화가 우선(AVIF/WebP).
4) 폰트: 코덱 선택보다 포맷 선택
- WOFF2: 내부가 Brotli 기반. 최우선 사용. 추가 Gzip/Brotli 불필요.
- WOFF/TTF/OTF: 전송 시 Gzip 또는 Brotli 가능하나, WOFF2로 변환이 더 큰 이득.
- 운영 팁: font-display: swap과 서브셋팅으로 바이트 자체를 줄이면 압축보다 효과적.
5) 정적 vs 동적: 어디서 CPU를 쓰고 어디서 아끼나
- 정적(빌드 산출물): 릴리스 때 사전압축(.br, .gz) 생성 → 서버/CDN은 파일만 서빙.
- 레벨: Brotli 10–11(시간이 걸려도 1회 비용), Gzip 6–7.
- 동적(런타임 생성): 응답 지연이 민감 → Brotli 4–6 또는 Gzip 5–6.
- 트래픽 많은 API는 CPU 프로파일링 후 레벨 상한 고정.
- 병렬 압축 워커/큐로 CPU 스파이크 방지.
6) 레벨 튜닝 가이드(현업 기준)
- Brotli
- 4–6: 실시간 응답용(지연↑ 방지)
- 7–9: 일반적 권장(효율/CPU 균형)
- 10–11: 정적 사전압축 전용
- Gzip
- 1–3: 미미한 이득, 의미 적음
- 5–7: 실무 Sweet Spot
- 8–9: CPU 대비 추가 이득 적음
7) 헤더·캐시 전략
- 협상: Accept-Encoding: br, gzip → 서버/CDN이 Brotli 우선 제공.
- Vary: Vary: Accept-Encoding으로 캐시 오염 방지.
- 캐시: 정적 파일은 public, max-age=31536000, immutable(+파일명 해시), 동적은 stale-while-revalidate로 변동성 흡수.
8) CDN/프록시 적용 체크리스트
- 사전압축 업로드(.br, .gz) 허용 여부 확인, 우선순위 br > gzip > identity.
- 원본 Pull 시 압축 전송 보존(re-compress 비활성).
- 이미지·비디오 MIME 타입은 압축 제외 룰 명시.
- 기능 플래그: Brotli on for text, Minimum size threshold(예: 1KB 이상만 압축).
- 로그로 압축률(원본/전송 바이트), CPU 사용률, TTFB p95를 주기 점검.
9) 보안·호환성
- 호환성: 현대 브라우저는 Brotli 지원. 구형 클라이언트는 Gzip 폴백으로 커버.
- TLS 영향: HTTPS 연결에서도 압축은 안전(HTTP 응답 본문). 단, 요청 압축은 크리덴셜 누출 취약점(CRIME/BREACH) 이슈로 비권장.
10) 실전 예시(개념 설정)
- 정적 app.[hash].js / .css / .svg
- 배포 시 .br(레벨 11) + .gz(레벨 7) 동시 생성
- 서버: try_files $uri.br $uri.gz $uri
- 동적 /api/feed
- Content-Type: application/json
- 서버: CPU 여유 시 Brotli 5, 아니면 Gzip 6
- Vary: Accept-Encoding, Cache-Control: max-age=60, stale-while-revalidate=600
- 이미지 /images/*.jpg|.png|.webp|.avif
- 압축 비활성(단, SVG만 Brotli)
11) 측정과 AB 테스트
- 지표: 전송 바이트, TTFB/LCP p75·p95, CPU 사용률, 에러율.
- 방법: 지역·디바이스·네트워크(3G/4G/5G) 별로 Brotli 레벨 5 vs Gzip 6 A/B.
- 해석: CPU 여유 없는 시간대에 TTFB 꼬리(p95/p99)가 늘면 레벨을 한 단계 낮추거나 Gzip 폴백.
12) 자주 묻는 질문(FAQ)
Q. “Brotli가 항상 최선”인가요?
A. 정적 텍스트에는 거의 그렇습니다. 다만 동적·CPU 한계 상황에서는 Gzip이 더 안정적일 수 있습니다.
Q. 이미지에도 Brotli를 켤까요?
A. SVG만 예외입니다. JPEG/PNG/WebP/AVIF는 자체 압축이라 재압축 금지가 원칙입니다.
Q. 레벨을 최고로 올리면 더 좋지 않나요?
A. 정적 사전압축은 OK. 그러나 런타임 압축은 레벨↑가 TTFB 악화로 돌아올 수 있습니다.
13) 요약 체크리스트
- 텍스트(HTML/CSS/JS/JSON): Brotli 우선, 정적은 레벨 10–11 사전압축, 동적은 5–7(또는 Gzip 6).
- 이미지: SVG만 압축, 비트맵은 포맷 최적화가 정답.
- 폰트: WOFF2 우선, 추가 압축 불필요.
- 캐시/헤더: Vary: Accept-Encoding, 정적 immutable, 동적 SWR.
- 운영: CPU·TTFB 꼬리를 보며 레벨 조정, 구형 클라이언트는 Gzip 폴백.
마무리
최적의 조합은 간단합니다. 정적 텍스트는 Brotli 고레벨, 동적 응답은 Brotli 중간 또는 Gzip, 이미지는 SVG만, 폰트는 WOFF2. 여기에 캐시·헤더·CDN 정책을 맞추면 바이트·지연·CPU가 동시에 안정화됩니다. 릴리스 파이프라인에 사전압축부터 넣고, 트래픽 상위 엔드포인트에서 레벨 A/B로 바로 검증해 보세요.