HTTP/2 서버 푸시 지원은 NGINX Plus R15에도 포함되어 있습니다.
기쁜 마음으로 다음 소식을 알려드립니다. NGINX 1.13.9에는 2018년 2월 20일 릴리스부터 HTTP/2 서버 푸시 지원이 포함됩니다. NGINX Plus 사용자를 위한 HTTP/2 서버 푸시 지원은 2018년 4월로 예정된 NGINX Plus R15 릴리스에 포함될 예정입니다.
서버 푸시는 HTTP/2 사양에 정의되어 있으며, 클라이언트가 곧 요청할 것으로 예상되는 리소스를 서버가 원격 클라이언트에 미리 푸시할 수 있도록 합니다. 이를 통해 페이지 로드 작업에 필요한 RTT(왕복 시간, 즉 요청과 응답에 걸리는 시간)를 하나 이상 줄여 사용자에게 더 빠른 응답을 제공할 수 있습니다.
서버 푸시를 사용하면 웹 페이지를 렌더링하는 데 필요한 스타일시트, 이미지 및 기타 리소스를 클라이언트에 미리 제공할 수 있습니다. 필요한 리소스만 푸시하도록 주의해야 하며, 클라이언트에 이미 캐시되어 있을 가능성이 높은 리소스는 푸시하지 마세요.
이 블로그 게시물에서는 다음 내용을 설명합니다:
- HTTP/2 서버 푸시를 위한 기본 구성
- HTTP/2 서버 푸시가 작동하는지 확인하는 방법 (브라우저 도구 또는
nghttp사용) - Automatically pushing content using the
Link헤더를 사용하여 콘텐츠 자동 푸시 - 콘텐츠를 선택적으로 푸시하기
- HTTP/2 서버 푸시의 효과 측정
HTTP/2 서버 푸시 구성
페이지를 로드할 때 리소스도 함께 푸시하려면 다음과 같이 http2_push 지시어를 사용합니다:
server { # Ensure that HTTP/2 is enabled for the server
listen 443 ssl http2;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
root /var/www/html;
# whenever a client requests demo.html, also push
# /style.css, /image1.jpg and /image2.jpg
location = /demo.html {
http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg;
}
}HTTP/2 서버 푸시 확인
다음 두 가지 방법 중 하나를 사용하여 서버 푸시가 적용되고 있는지 쉽게 확인할 수 있습니다:
- 웹 브라우저의 개발자 도구
- 명령줄 HTTP/2 클라이언트(예:
nghttp
개발자 도구로 확인하기(Google Chrome)
다음은 Google Chrome을 예로 들어 웹 브라우저의 개발자 도구를 사용하여 서버 푸시가 적용되고 있는지 확인하는 방법입니다. 그림에서 Chrome 개발자 도구의 Initiator 열은 Network 탭에 표시되며, /demo.html 요청의 일부로 여러 리소스가 클라이언트에 푸시되었음을 나타냅니다.

명령줄 클라이언트로 확인하기 (nghttp)
웹 브라우저 도구 외에도 nghttp2.org 프로젝트의 nghttp 명령줄 클라이언트를 사용하여 서버 푸시가 적용되고 있는지 확인할 수 있습니다. nghttp 명령줄 클라이언트는 GitHub에서 다운로드하거나, 사용 가능한 경우 운영 체제에 맞는 패키지를 설치할 수 있습니다. Ubuntu에서는 nghttp2-client 패키지를 사용하세요.
출력에서 별표(*)는 서버가 푸시한 리소스를 나타냅니다.
$ nghttp -ans https://example.com/demo.htmlid responseEnd requestStart process code size request path
13 +84.25ms +136us 84.11ms 200 492 /demo.html
2 +84.33ms * +84.09ms 246us 200 266 /style.css
4 +261.94ms * +84.12ms 177.83ms 200 40K /image2.jpg
6 +685.95ms * +84.12ms 601.82ms 200 173K /image1.jpg클라이언트에 리소스 자동 푸시
많은 경우 푸시하려는 리소스를 NGINX 구성 파일에 나열하는 것은 번거롭거나 아예 불가능할 수도 있습니다. 따라서 NGINX는 Link 프리로드 헤더를 가로채 해당 헤더에 지정된 리소스를 푸시하는 방식도 지원합니다. 프리로드를 활성화하려면 구성에 http2_push_preload 지시어를 포함하세요:
server { # Ensure that HTTP/2 is enabled for the server
listen 443 ssl http2;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
root /var/www/html;
# Intercept Link header and initiate requested Pushes
location = /myapp {
proxy_pass http://upstream;
http2_push_preload on;
}
}예를 들어 NGINX가 프록시(HTTP, FastCGI 또는 기타 트래픽 유형용)로 작동하는 경우, 업스트림 서버는 응답에 다음과 같은 Link 헤더를 추가할 수 있습니다:
Link: </style.css>; as=style; rel=preloadNGINX는 이 헤더를 가로채 /style.css의 서버 푸시를 시작합니다. Link 헤더의 경로는 절대 경로여야 하며, ./style.css와 같은 상대 경로는 지원되지 않습니다. 경로에는 선택적으로 쿼리 문자열을 포함할 수 있습니다.
여러 객체를 푸시하려면 여러 개의 Link 헤더를 제공하거나, 더 좋은 방법으로 모든 객체를 쉼표로 구분된 목록에 포함할 수 있습니다:
Link: </style.css>; as=style; rel=preload, </favicon.ico>; as=image; rel=preloadNGINX가 미리 로드된 리소스를 푸시하지 않도록 하려면 헤더에 nopush 매개변수를 추가합니다:
# Resource is not pushedLink: </nginx.png>; as=image; rel=preload; nopushWhen http2_push_preload을 활성화하면 NGINX 구성에서 응답 헤더를 설정하여 프리로드 서버 푸시를 시작할 수도 있습니다:
add_header Link "</style.css>; as=style; rel=preload";클라이언트에 리소스를 선택적으로 푸시하기
HTTP/2 사양에서는 리소스를 푸시할지 여부를 판단하는 문제를 다루지 않습니다. 클라이언트에 리소스가 필요할 가능성이 높고 해당 리소스가 이미 캐시되어 있을 가능성이 낮다는 것을 모두 알고 있는 경우에만 리소스를 푸시하는 것이 가장 좋습니다.
가능한 접근 방식 중 하나는 클라이언트가 사이트를 처음 방문할 때만 리소스를 푸시하는 것입니다. 예를 들어 세션 쿠키가 있는지 확인하고, Link 헤더를 조건부로 설정하여 세션 쿠키가 없을 때만 리소스를 미리 로드할 수 있습니다.
클라이언트가 정상적으로 동작하여 이후 요청에 쿠키를 포함한다고 가정하면, 다음과 같이 구성할 경우 NGINX는 브라우저 세션당 한 번만 리소스를 클라이언트에 푸시합니다:
server {
listen 443 ssl http2 default_server;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
root /var/www/html;
http2_push_preload on;
location = /demo.html {
add_header Set-Cookie "session=1";
add_header Link $resources;
}
}
map $http_cookie $resources {
"~*session=1" "";
default "</style.css>; as=style; rel=preload, </image1.jpg>; as=image; rel=preload, </image2.jpg>; as=image; rel=preload";
}HTTP/2 서버 푸시의 효과 측정
서버 푸시의 효과를 측정하기 위해 별도의 스타일시트를 참조하는 간단한 테스트 페이지인 /demo.html을 만들었습니다. 이 페이지는 /style.css을 참조하며, 해당 스타일시트는 다시 두 개의 이미지를 참조합니다. 다음 세 가지 구성에서 페이지 로드 시간을 테스트했습니다:
- 순차적
GET요청(최적화 없음) – 브라우저는 리소스가 필요하다는 것을 확인했을 때 해당 리소스를 로드했습니다 - 프리로드 힌트 – 브라우저가 종속 리소스를 로드하도록 알리기 위해 첫 번째 응답에 프리로드 힌트(
Link헤더)가 포함되었습니다 - 서버 푸시 (HTTP/2 전용) – 종속 리소스를 브라우저에 미리 푸시했습니다

HTTP, HTTPS 또는 HTTP/2를 사용하여 각 구성에 대해 여러 차례 테스트를 실행했습니다. 처음 두 구성은 세 프로토콜 모두에 적용되며, 서버 푸시는 HTTP/2에만 적용됩니다.
Chrome 개발자 도구를 사용하여 동작을 측정했습니다. 각 구성에서 가장 일반적으로 나타나는 동작을 평가하고 평균을 구했으며, 각 방법의 기계적 효과를 보여 주기 위해 소요 시간을 링크의 RTT(ping으로 측정)와 연관 지어 분석했습니다.

몇 가지 기본적인 관찰 사항
- DOM 로드는 새 연결을 시작하고 demo.html 페이지를 가져오는 데 걸리는 시간입니다. 스타일시트는 CSS 리소스를 가져오는 데 걸리는 시간입니다.
- HTTP를 통한 연결 설정에는 1 RTT가 소요되며, HTTPS 및 HTTP/2의 경우에는 2 RTT가 소요됩니다.
- HTML 및 CSS 리소스의 페이로드는 최대 전송 단위(MTU) 크기보다 작으므로
GET작업은 약 1 RTT 내에 완료됩니다.
결과 해석: 프리로드 힌트
- CSS 리소스는 HTML 리소스 내에서 직접 참조되고 HTML 리소스가 빠르게 전송되므로, 미리 로드 힌트가 미치는 영향은 미미합니다. 브라우저는 HTML 페이지가 전송되는 즉시 CSS 요청을 시작합니다.
- 프리로드 힌트를 사용하면 CSS 리소스에 선언된 리소스(여기서는 두 이미지)의 다운로드를 빠르게 시작할 수 있습니다. 프리로드 힌트를 사용하면 다운로드를 1 RTT 더 빠르게 시작할 수 있습니다.
- 프리로드 힌트를 사용하면 전체적으로 1 RTT 이상을 단축할 수 있습니다. 리소스를 병렬로 다운로드할 때 브라우저는 하나 이상의 추가 연결을 열어야 합니다. 성능은 느린 요청(응답 크기가 큰 요청)이 먼저 처리되도록 예약되는지, 아니면 새 연결이 열리는 동안 지연되는지에 따라 달라집니다. 이처럼 예측할 수 없는 요청 순서로 인해 HTTP 및 HTTP/2에서는 1 RTT, HTTPS에서는 2 RTT가 단축됩니다.
결과 해석: 서버 푸시
- 서버 푸시는 프리로드 힌트 방식보다 시간을 추가로 1 RTT 단축했습니다. 푸시 ‘응답’은 첫 번째 요청에 대한 응답과 동시에 시작된 반면, 프리로드 힌트 응답에는 1 RTT의 지연이 발생했습니다. 이는 첫 번째 요청에 대한 응답에 0.5 RTT, 프리로드
GET요청에 0.5 RTT가 소요되었기 때문입니다.
테스트 참고 사항
- 각 구성마다 여러 차례 테스트를 실행했습니다. 각 테스트는 브라우저 캐시가 비어 있고 NGINX 서버에 설정된 keepalive 연결이 없는 상태에서 시작했습니다. NGINX 지시어인
keepalive_timeout과http2_idle_timeout을 사용하여 keepalive 연결을 빠르게 종료했습니다. - 현재로서는 Chrome에 글꼴 리소스를 푸시하는 것이 불가능해 보이는데, 이는 아마도 알려진 문제 때문일 수 있습니다. Chrome은 글꼴 리소스가 이미 푸시된 경우에도 이를 명시적으로 요청합니다.
- 각 테스트 전에 브라우저 캐시를 명시적으로 삭제했으며, 모든 콘텐츠는 만료된 캐시 제어 헤더와 함께 제공되었습니다.
- Chrome은 미리 로드된 리소스를 캐시합니다. 캐싱을 사용 중지해도 이러한 캐시된 리소스가 항상 무시되는 것은 아니며, 명시적으로 ‘브라우저 캐시 지우기’ 작업을 수행해도 항상 삭제되는 것은 아닙니다. (Chrome에서 캐싱을 사용 중지하는 한 가지 방법은 개발자 도구의 캐시 사용 중지 체크박스를 네트워크 탭에서 선택하는 것입니다. 브라우저 캐시를 지우려면 개발자 도구를 연 상태에서 브라우저 새로고침 버튼을 마우스 오른쪽 버튼으로 클릭하고 캐시 비우기 및 강력 새로고침을 선택하면 됩니다.)
- 콘텐츠를 미리 로드하려는 일부 시도에서는 Chrome이 캐시된 사본의 유효성을 다시 확인하지 못한 후 리소스를 일반적인 방식으로 다운로드했습니다. 이러한 시도는 측정 결과에 포함되지 않았습니다.
- Chrome은 이전에 허용된 자체 서명 인증서를 사용하는 모든 새 SSL 연결에 불필요한 2‑RTT 지연을 추가합니다. 이 2‑RTT 지연을 방지하기 위해 테스트에는 CA가 서명한 Let’s Encrypt 인증서를 사용했습니다.
- DNS 지연 문제는 로컬 /etc/hosts 파일을 수정하여 해결했습니다.
- 이러한 간단한 테스트에서는 클라이언트에 이미 리소스의 캐시된 사본이 있는 경우 서버 푸시가 미치는 영향을 측정하지 않았습니다. 테스트에서는 각 테스트를 실행하기 전에 모든 캐시를 지웠으며, 대부분의 푸시는 너무 빨리 이루어져 취소할 수 없었습니다.
결론
이 테스트는 프리로드 힌트와 서버 푸시의 작동 방식을 명확히 보여 주기 위해 의도적으로 단순하게 구성했습니다. 단순한 상황에서 서버 푸시는 프리로드 힌트보다 1‑RTT만큼 성능을 개선하며, 최적화되지 않은 순차적 GET 요청 및 종속 리소스 탐색과 비교하면 더 큰 성능 향상을 제공합니다.
보다 현실적인 사용 사례에는 훨씬 더 많은 변수가 있습니다. 여러 종속 리소스와 여러 소스가 있을 수 있으며, 이미 캐시되어 있거나 당장 필요하지 않은 리소스를 푸시해 대역폭이 낭비될 가능성도 있습니다. 브라우저 간의 차이도 성능에 영향을 미칩니다. 실제 결과는 이 간단한 테스트와 분명히 다를 수 있습니다.
예를 들어 Chrome 팀은 서버 푸시를 언제 도입해야 하는지에 관한 몇 가지 구체적인 권장 사항을 발표했으며, 더 복잡한 사이트에서 최적화를 적용하지 않은 경우, 프리로드 힌트를 사용한 경우, HTTP/2를 통한 서버 푸시를 사용한 경우의 효과를 비교 측정했습니다. Chrome 팀의 「HTTP/2 푸시를 위한 경험 법칙」 보고서는 프로덕션 환경에 HTTP/2 서버 푸시 도입을 고려하는 사람이라면 읽어볼 만합니다.
실용적인 결론은 필요한 리소스를 미리 파악할 수 있다면 업스트림 서버가 프리로드 힌트를 보내도록 하는 것이 실질적인 이점이 있다는 것입니다. 이러한 리소스를 푸시함으로써 얻는 추가 이점은 작지만 측정 가능하며, 대역폭 낭비와 필요한 리소스의 지연을 초래할 수도 있습니다. 모든 서버 푸시 구성은 신중하게 테스트하고 모니터링해야 합니다.
부록: HTTP/2 푸시는 어떻게 작동하나요?
아래 정보는 Jake Archibald가 매우 상세하게 작성한 HTTP/2 푸시는 생각보다 어렵다라는 블로그 게시물의 연구 내용을 일부 바탕으로 합니다.
HTTP/2 서버 푸시는 일반적으로 클라이언트가 리소스를 요청할 때 종속 리소스를 미리 전송하는 데 사용됩니다. 예를 들어 클라이언트가 웹 페이지를 요청하면 서버는 해당 페이지에 필요한 스타일시트, 글꼴, 이미지를 클라이언트에 푸시할 수 있습니다.
클라이언트가 HTTP/2 연결을 설정하면 서버는 해당 연결을 통해 하나 이상의 서버 푸시 응답을 시작할 수 있습니다. 이러한 푸시는 클라이언트가 명시적으로 요청하지 않은 리소스를 전송합니다.
클라이언트는 푸시를 거부하기 위해 RST_STREAM 프레임을 전송하거나 푸시를 수락할 수 있습니다. 클라이언트는 푸시된 콘텐츠를 HTTP/2 연결과 연계된 로컬 ‘푸시 캐시’에 저장합니다.
나중에 클라이언트가 이미 설정된 HTTP/2 연결을 사용하여 리소스를 요청하면, 해당 연결의 푸시 캐시에서 요청에 대한 응답이 완료되었거나 전송 중인지 확인합니다. 캐시된 리소스가 있으면 해당 리소스에 대해 새로운 HTTP/2 요청을 보내는 대신 이를 우선 사용합니다.
푸시된 리소스는 (a) 사용되거나 (b) HTTP/2 연결이 종료될 때까지 연결별 푸시 캐시에 유지됩니다:
- 리소스가 사용되면 클라이언트가 복사본을 가져오고 푸시 캐시의 항목은 삭제됩니다. 리소스를 캐시할 수 있는 경우 클라이언트는 해당 복사본을 HTTP 페이지 캐시에 저장할 수 있습니다.
- 어떤 이유로든 HTTP/2 연결이 종료되면 해당 연결의 로컬 푸시 캐시가 삭제됩니다.
이는 다음과 같은 몇 가지 의미를 갖습니다:
- 푸시된 콘텐츠가 더 최신이더라도 브라우저의 HTTP 페이지 캐시에 있는 콘텐츠가 푸시 캐시의 콘텐츠보다 우선적으로 사용됩니다.
- HTTP/2 연결은 서로 다른 페이지 로드 간에 공유될 수 있습니다. 한 페이지를 로드할 때 푸시된 리소스는 다른 페이지를 로드할 때 요청되면 사용할 수 있습니다.
- 자격 증명이 포함된 요청은 자격 증명이 없는 요청과 다른 HTTP/2 연결을 사용합니다. 예를 들어 교차 출처 요청(자격 증명 포함)을 통해 푸시된 리소스는 브라우저가 해당 리소스를 자격 증명 없이 요청할 경우 찾지 못할 수 있습니다.
Jake Archibald의 블로그 게시물인 HTTP/2 푸시는 생각보다 더 어렵다에서 훨씬 더 자세한 문제 목록을 확인할 수 있습니다.
HTTP/2 서버 푸시는 흥미로운 기능입니다. HTTP/2 서버 푸시 구성을 철저히 테스트하고, 프리로드 힌트를 사용하는 편이 캐시를 고려한 동작을 더 예측 가능하게 만드는 경우에는 이를 대신 사용할 수 있도록 준비하세요.
작성자 소개

관련 블로그 게시물
시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.
F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.
Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.
진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.
NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.
Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.