블로그 | NGINX

NGINX 1.13.9를 사용한 HTTP/2 서버 푸시 소개

NGINX-F5-수평-검정-유형-RGB의 일부
오웬 개렛 썸네일
오웬 개렛
2018년 2월 20일 게시

NGINX Plus R15 에는 HTTP/2 서버 푸시에 대한 지원도 포함되어 있습니다.

2018년 2월 20일 에 출시된 NGINX 1.13.9에 HTTP/2 서버 푸시 지원이 포함되었다는 소식을 전해드리게 되어 기쁩니다. NGINX Plus 사용자를 위해, 2018년 4월에 출시될 NGINX Plus R15 릴리스에 HTTP/2 서버 푸시 지원이 포함될 예정입니다.

HTTP/2 사양에 정의된 서버 푸시를 사용하면 서버가 클라이언트가 곧 해당 리소스를 요청할 수도 있다는 것을 예상하고 원격 클라이언트에 리소스를 미리 푸시할 수 있습니다. 이렇게 하면 페이지 로드 작업에서 RTT(왕복 시간, 즉 요청과 응답에 필요한 시간) 수를 1RTT 이상 줄일 수 있고, 이를 통해 사용자에게 더 빠른 응답을 제공할 수 있습니다.

서버 푸시는 클라이언트에게 웹 페이지를 렌더링하는 데 필요한 스타일 시트, 이미지 및 기타 리소스를 제공하는 데 사용될 수 있습니다. 필요한 리소스만 푸시하도록 주의해야 합니다. 클라이언트가 이미 캐시했을 가능성이 있는 리소스는 푸시하지 마세요.

이 블로그 게시물에서는 다음 내용을 설명합니다.

HTTP/2 서버 푸시 구성

페이지 로드와 함께 리소스를 푸시하려면 다음과 같이 http2_push 지시문을 사용합니다.

server { # 서버에 대해 HTTP/2가 활성화되어 있는지 확인하세요 listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # 클라이언트가 demo.html을 요청할 때마다 # /style.css, /image1.jpg 및 /image2.jpg도 푸시합니다 location = /demo.html { http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg; } }

HTTP/2 서버 푸시 확인

다음 두 가지 방법 중 하나를 사용하여 서버 푸시가 적용되었는지 쉽게 확인할 수 있습니다.

  • 웹 브라우저의 개발자 도구
  • nghttp 와 같은 명령줄 HTTP/2 클라이언트

개발자 도구로 확인(Google Chrome)

다음은 Google Chrome을 예로 들어, 웹 브라우저의 개발자 도구를 사용하여 서버 푸시가 적용되는지 확인하는 방법입니다. 그림에서 Chrome 개발자 도구의 네트워크 탭에 있는 개시자 열은 /demo.html 에 대한 요청의 일부로 여러 리소스가 클라이언트에 푸시되었음을 나타냅니다.

Initiator 열은 서버 푸시가 리소스를 전송하는 데 사용되었음을 나타냅니다.

명령줄 클라이언트( nghttp )로 확인

웹 브라우저 도구 외에도 nghttp2.org 프로젝트의 nghttp 명령줄 클라이언트를 사용하여 서버 푸시가 제대로 작동하는지 확인할 수 있습니다. GitHub 에서 nghttp 명령줄 클라이언트를 다운로드하거나, 가능한 경우 적절한 운영 체제 패키지를 설치할 수 있습니다. Ubuntu의 경우 nghttp2-client 패키지를 사용하세요.

출력에서 별표(*)는 서버에서 푸시된 리소스를 표시합니다.

$ nghttp -ans https://example.com/demo.html id responseEnd 요청 시작 프로세스 코드 크기 요청 경로 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 { # 서버에 대해 HTTP/2가 활성화되어 있는지 확인합니다. listen 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # 링크 헤더를 가로채서 요청된 푸시를 시작합니다. location = /myapp { proxy_pass http://upstream; http2_push_preload on; } }

예를 들어, NGINX가 프록시(HTTP, FastCGI 또는 기타 트래픽 유형)로 작동하는 경우 업스트림 서버는 다음과 같은 Link 헤더를 응답에 추가할 수 있습니다.

링크: </style.css>; as=style; rel=preload

NGINX는 이 헤더를 가로채서 /style.css 의 서버 푸시를 시작합니다. Link 헤더의 경로는 절대 경로여야 합니다. ./style.css 와 같은 상대 경로는 지원되지 않습니다. 경로에는 선택적으로 쿼리 문자열이 포함될 수 있습니다.

여러 객체를 푸시하려면 여러 Link 헤더를 제공하거나 더 나은 방법으로 모든 객체를 쉼표로 구분된 목록에 포함할 수 있습니다.

링크: </style.css>; as=style; rel=preload, </favicon.ico>; as=image; rel=preload

NGINX가 미리 로드된 리소스를 푸시하지 않도록 하려면 헤더에 nopush 매개변수를 추가하세요.

# 리소스가 푸시되지 않았습니다. 링크: </nginx.png>; as=image; rel=preload; nopush

http2_push_preload가 활성화된 경우 NGINX 구성에서 응답 헤더를 설정하여 사전 로드 서버 푸시를 시작할 수도 있습니다.

add_header 링크 "</style.css>; as=style; rel=preload";

클라이언트에게 선택적으로 리소스 제공

HTTP/2 사양은 리소스를 푸시할지 여부를 결정하는 문제를 다루지 않습니다. 분명히, 리소스가 필요할 가능성이 높고 이미 캐시되었을 가능성이 낮은 경우에만 클라이언트에 리소스를 푸시하는 것이 가장 좋습니다.

한 가지 가능한 접근 방식은 사이트를 처음 방문한 클라이언트에게만 리소스를 제공하는 것입니다. 예를 들어 세션 쿠키가 있는지 테스트하고 Link 헤더를 조건부로 설정하면 세션 쿠키가 없는 경우에만 리소스가 미리 로드됩니다.

클라이언트가 정상 작동하고 후속 요청에 쿠키를 포함한다고 가정하면 다음 구성을 사용하면 NGINX는 브라우저 세션당 한 번만 리소스를 클라이언트에 푸시합니다.

서버 {
청취 443 ssl http2 기본 서버;

ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;

루트 /var/www/html;
http2_push_preload 켜짐;

위치 = /demo.html {
add_header 쿠키 설정 "세션=1";
add_header 링크 $resources;
}
}

맵 $http_cookie $resources {
"~*세션=1" "";
기본 "</style.css>; as=style; rel=사전 로드, </image1.jpg>; as=image; rel=사전 로드, </image2.jpg>; as=image; rel=사전 로드";
}

HTTP/2 서버 푸시 효과 측정

서버 푸시의 효과를 측정하기 위해 /style.css 라는 별도의 스타일 시트를 참조하는 간단한 테스트 페이지 /demo.html을 만들었습니다. 스타일시트는 또한 두 개의 이미지를 참조합니다. 우리는 세 가지 다른 구성을 사용하여 페이지 로드 시간을 테스트했습니다.

  • 순차적 GET (최적화 없음) – 브라우저는 필요한 리소스를 발견했을 때 리소스를 로드했습니다.
  • 사전 로드 힌트 - 사전 로드 힌트( 링크 헤더)는 브라우저에 종속성을 로드하도록 알리기 위해 첫 번째 응답에 포함되었습니다.
  • 서버 푸시 (HTTP/2 전용) – 종속성이 브라우저에 미리 푸시되었습니다.
HTTP/2와 서버 푸시의 영향을 측정하기 위해 세 가지 구성이 테스트되었습니다.

우리는 HTTP, HTTPS 또는 HTTP/2를 사용하여 각 구성에 대해 여러 번의 테스트를 수행했습니다. 처음 두 구성은 세 가지 프로토콜 모두에 적용되고 서버 푸시는 HTTP/2에만 적용됩니다.

동작은 Chrome 개발자 도구를 사용하여 측정되었습니다. 각 구성의 가장 흔한 동작을 평가하여 평균화했으며, 각 방법의 기계적 효과를 설명하기 위해 시간을 링크의 RTT( ping을 사용하여 측정)와 상관시켰습니다.

각 구성에서 많은 왕복이 발생했음을 보여주는 테스트 결과

몇 가지 기본적인 관찰

  • DOM이 로드되면 새로운 연결을 시작하고 demo.html 페이지를 검색하는 시간입니다. 스타일시트는 CSS 리소스를 검색하는 시간입니다.
  • HTTP를 통해 연결을 설정하는 데는 1RTT가 걸리고, HTTPS와 HTTP/2의 경우 2RTT가 걸립니다.
  • HTML과 CSS 리소스에 대한 페이로드는 최대 전송 단위(MTU) 크기보다 작으므로 GET 작업은 약 1 RTT로 완료됩니다.

결과 해석: 사전 로드 힌트

  • 사전 로드 힌트는 CSS 리소스에 미치는 영향이 미미합니다. 왜냐하면 HTML 리소스 내에서 직접 참조되고 HTML 리소스가 빠르게 전달되기 때문입니다. 브라우저는 HTML 페이지가 전달되자마자 CSS 요청을 시작합니다.
  • 사전 로드 힌트는 CSS 리소스에 선언된 리소스(여기서는 두 개의 이미지)의 다운로드를 빠르게 시작하는 효과가 있습니다. 사전 로드 힌트를 사용하면 다운로드를 1 RTT 더 빨리 시작할 수 있습니다.
  • 사전 로드 힌트를 사용하면 순 절감 효과가 1RTT 이상일 수 있습니다. 리소스를 병렬로 다운로드할 때 브라우저는 하나 이상의 추가 연결을 열어야 합니다. 성능은 느린 요청(큰 응답)을 먼저 예약하는지, 아니면 새로운 연결이 열리는 동안 지연하는지에 따라 달라집니다. 예측할 수 없는 요청 순서로 인해 HTTP 및 HTTP/2의 경우 1‑RTT가 빨라지고 HTTPS의 경우 2‑RTT가 빨라집니다.

결과 해석: 서버 푸시

  • 서버 푸시는 사전 로드 힌트 시간을 1 RTT 더 개선했습니다. 푸시 "응답"은 첫 번째 요청에 대한 응답과 동시에 시작되었지만 사전 로드 힌트 응답은 1 RTT 지연이 발생했습니다. 즉, 첫 번째 요청에 대한 응답에 대한 0.5 RTT와 사전 로드 GET 요청에 대한 0.5 RTT가 발생했습니다.

테스트 노트

  • 각 구성에 대해 여러 번의 테스트 실행이 있었습니다. 각 실행은 브라우저 캐시가 비어 있고 NGINX 서버와의 연결 유지가 이루어지지 않은 상태에서 시작되었습니다. NGINX 명령어 keepalive_timeouthttp2_idle_timeout은 keepalive 연결을 빠르게 닫는 데 사용되었습니다.
  • 현재로선 알려진 문제 때문에 Chrome에 글꼴 리소스를 푸시하는 것이 불가능한 것으로 보입니다. 크롬은 이미 푸시된 경우에도 글꼴 리소스에 대한 명시적 요청을 합니다.
  • 각 테스트를 실시하기 전에 브라우저 캐시를 명확하게 지우는 데 주의를 기울였으며, 모든 콘텐츠는 만료된 캐시 제어 헤더와 함께 제공되었습니다.
  • Chrome은 미리 로드된 리소스를 캐시합니다. 캐싱을 비활성화하면 이러한 캐시된 리소스가 일관되게 무시되지 않으며 명시적인 "브라우저 캐시 지우기" 작업으로 일관되게 지워지지 않습니다. (Chrome에서 캐싱을 비활성화하는 한 가지 방법은 개발자 도구의 네트워크 탭에서 캐시 비활성화 확인란을 선택하는 것입니다. 브라우저 캐시를 지우려면 개발자 도구를 연 상태에서 브라우저 새로 고침 버튼을 마우스 오른쪽 버튼으로 클릭하고 캐시 비우기 및 강제 다시 로드를 선택하세요.
  • 콘텐츠를 미리 로드하려는 시도 중 일부로 인해 Chrome이 캐시된 사본을 다시 검증하지 못하고 정상적으로 리소스를 다운로드하지 못했습니다. 이러한 시도는 측정에 반영되지 않았습니다.
  • Chrome은 이전에 승인된 자체 서명 인증서를 사용하는 모든 새로운 SSL 연결에 불필요한 2‑RTT 지연을 추가합니다. 이 2‑RTT 지연을 방지하기 위해 CA에서 서명한 Let’s Encrypt 인증서를 사용하여 테스트를 수행했습니다.
  • DNS 지연은 로컬 /etc/hosts 파일을 편집하여 해결되었습니다.
  • 이러한 간단한 테스트에서는 클라이언트가 이미 리소스의 캐시된 사본을 가지고 있는 경우 서버 푸시의 효과를 측정하려고 하지 않았습니다. 테스트에서 모든 캐시는 각 테스트 전에 지워졌고, 대부분의 푸시는 취소하기에는 너무 빨랐습니다.

결론

이 테스트는 사전 로드 힌트와 서버 푸시의 메커니즘을 강조하기 위해 의도적으로 단순하게 만들어졌습니다. 서버 푸시는 간단한 상황에서 사전 로드 힌트보다 1‑RTT 개선을 제공하고, 최적화되지 않은 순차적 GET 요청 및 종속 리소스 검색과 비교하면 더 큰 개선을 제공합니다.

보다 현실적인 사용 사례에는 훨씬 더 많은 변수가 있습니다. 여러 개의 종속 리소스, 여러 소스, 이미 캐시되거나 즉시 필요하지 않은 리소스를 푸시하여 대역폭을 낭비할 가능성도 있습니다. 브라우저 불일치도 성능에 영향을 미칩니다. 이 간단한 테스트를 통해 여러분은 분명 많은 것을 얻을 수 있을 것입니다.

예를 들어, Chrome 팀은 서버 푸시를 배포하는 시기에 대한 자세한 권장 사항을 게시했으며, 더 복잡한 사이트에서 최적화 없음, 사전 로드 힌트, HTTP/2를 통한 서버 푸시의 효과를 비교하기 위해 측정을 수행했습니다. 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 연결이 닫힐 때까지 연결당 푸시 캐시에 남아 있습니다.

  1. 리소스가 사용되면 클라이언트는 복사본을 만들고 푸시 캐시의 항목은 삭제됩니다. 리소스가 캐시 가능한 경우 클라이언트는 해당 리소스의 사본을 HTTP 페이지 캐시에 캐시할 수 있습니다.
  2. 어떤 이유로든 HTTP/2 연결이 닫히면 로컬 푸시 캐시가 삭제됩니다.

이는 여러 가지 의미를 갖습니다.

  • 푸시된 콘텐츠가 더 최신이더라도, 브라우저의 HTTP 페이지 캐시에 있는 콘텐츠는 푸시 캐시에 있는 콘텐츠보다 우선적으로 사용됩니다.
  • HTTP/2 연결은 여러 페이지 로드에서 공유될 수 있습니다. 한 페이지가 로드될 때 푸시되는 리소스는 다른 페이지가 로드될 때 요청될 때 사용될 수 있습니다.
  • 자격 증명이 있는 요청은 자격 증명이 없는 요청과 다른 HTTP/2 연결을 사용합니다. 예를 들어, 교차 출처 요청(자격 증명)으로 푸시된 리소스는 브라우저가 리소스에 대해 자격 증명이 없는 요청을 하는 경우 찾을 수 없습니다.

Jake Archibald의 HTTP/2 푸시는 생각보다 힘들다는 블로그 게시물에서 훨씬 더 자세한 문제 목록을 검토할 수 있습니다.

HTTP/2 서버 푸시는 흥미로운 기능입니다. HTTP/2 서버 푸시 구성을 철저히 테스트하고, 더 예측 가능하고 캐시를 인식하는 동작이 발생하는 경우 사전 로드 힌트로 대체할 준비를 하세요.


"이 블로그 게시물에는 더 이상 사용할 수 없거나 더 이상 지원되지 않는 제품이 참조될 수 있습니다. 사용 가능한 F5 NGINX 제품과 솔루션에 대한 최신 정보를 보려면 NGINX 제품군을 살펴보세요. NGINX는 이제 F5의 일부가 되었습니다. 이전의 모든 NGINX.com 링크는 F5.com의 유사한 NGINX 콘텐츠로 리디렉션됩니다."