[Nginx] HTTP/2

반응형

이번글에서는 nginx에서 HTTP/2를 사용해 성능을 향상시키는 방법에 대해 알아보도록 하겠습니다.

1. HTTP/2란?

기존의 HTTP/1.1을 개선한 차세대 HTTP 프로토콜입니다.

2. HTTP/1.1 vs HTTP/2

HTTP/1.1과의 차이점은 아래와 같습니다.

2-1) binary protocol

HTTP/2는 binary protocol을 사용해 데이터를 전송함으로써 기존의 HTTP/1.1보다 월등히 compact하게 data를 전송합니다. 또한, 이를 통해 data transfer 중에 일어날 수 있는 error를 최소화할 수 있습니다.

반면에 기존의 HTTP/1.1은 textual protocol입니다.

2-2) compressed header

HTTP/2은 comprssed header를 사용해 data를 전송함으로써 binary protocol과 마찬가지로 data의 전송시간을 줄일 수 있습니다.

2-3) persistent connection & multiplex streaming

HTTP/2는 하나의 TCP 연결을 사용하여 복수의 HTTP 요청/응답을 주고받을 수 있습니다. 또한 이러한 persistent connection은 multiplex streaming 기능을 지원합니다.

multiplex streaming이란 multiple access에 대한 response를 하나의 binary data로 묶어 전송할 수 있는 기술입니다.

예를들어 HTML/JS/CSS에 대한 각각의 요청을 하나의 stream of binary data로 combine해 single connection을 통해 전송할 수 있습니다.

만약 HTTP/1.1을 사용한다면 위의 HTML/JS/CSS의 3개의 data를 요청하기위해선 resource당 하나의 connection을 사용해야합니다.

2-4) Server Push

HTTP/2는 client가 요청한 resource에 연관된 다른 resource들을 임의로 client에 초기 요청의 결과값과 함께 push할 수 있습니다. 이를 통해 클라이언트의 요청을 최소화해 성능 향상을 이끌어냅니다.

예를 들어 클라이언트가 index.html을 요청한경우 HTTP/2는 index.html에서 사용되는 script.js와 style.css를 index.html과 함께 임의로 클라이언트에게 push 할 수 있습니다.

3. Connection

clinet와 server간의 new connection을 open하는 것은 time consuming process이며, 특정 domain에 동시에 connection할 수 있는 number의 갯수에는 limit이 정해져 있습니다.

따라서 이를 줄이기위해 대다수의 developer들은 multiple javascript/css 파일들을 하나의 single file로 concatenate 하기위해 노력합니다.

openning new connection은 client와 server간의 handshake라는 일종의 동의 과정이 필요합니다.

또한 이러한 과정을 수행하기위해 매번 client와 server간에 header를 매번 전달해야만 합니다.

자, 그렇다면 basic HTML page를 요청할때 얼마나 많은 connection이 생성이 되는지 HTTP/1.1와 HTTP/2를 비교해보도록 하겠습니다. 😎

3-1) HTTP/1.1

먼저 HTTP/1.1이 index.html을 요청했다고 가정하겠습니다.

이때 HTTP/1.1은 index.html을 return받기위해 1개의 connection을 사용합니다.

이후 client는 return받은 index.html을 살펴보고 index.html에 필요한 linked resource을 확인합니다. 이때의 linked resourec는 js/css 파일 등이 될 수 있습니다.

이후 client는 index.html을 요청했을때와 동일하게 각각의 resource에 대한 요청을 각각의 connection을 생성해 수행하게 됩니다.

따라서 HTTP/1.1 클라이언트는 총 3개의 connection을 사용하게 됩니다.

너무 비효울적이지 않나요??.. 😅

현대의 대다수의 websites는 multiple js/css/img 파일들로 이루어져 있습니다. 따라서 하나의 page를 load하는데 최소 15+ 이상의 connection을 필요로하게됩니다. 이로 인해 some new connections들은 other connection이 closed 될때까지 대기해야되는 경우도 생기기됩니다.

이와같은 HTTP/1.1의 비효율적인 data trnasfer를 개선하기위해 HTTP/2가 등장하게 되었습니다. 😎

3-2) HTTP/2

이제 HTTP/2의 경우를 살펴보겠습니다.

HTTP/2를 사용하면 index.html 파일을 요청하고 linked resource인 js/css data를 return 받는데 1개의 connection만 사용하면 됩니다.

HTTP/2는 persistent connection와 multiplex streaming 기능을 제공하기 때문입니다. 따라서 HTTP/1.1에 비해 현저히 적은수의 connection을 사용하게됩니다.

4. Set HTTP/2

이제 Nginx에 HTTP/2를 적용해보도록 하겠습니다.

HTTP/2를 사용하기위해선 HTTPS를 반드시 사용해야합니다.

따라서 먼저 HTTPS를 적용하도록 하겠습니다. 이번 실습에서 사용할 nginx.conf 파일은 다음과 같습니다.

nginx.conf

worker_processes auto;

events {
    worker_connections  1024;
}


http {
        include mime.types;

        server {
                listen 80;
                root /sites/demo;
                index index.php index.html;

                location / {
                        try_files $uri $uri/ =404;
                }

                location ~\.php$ {
                        # Pass php requests to the php-fpm service (fastcgi)
                        include fastcgi.conf;
                        fastcgi_pass unix:/run/php/php7.10fpm.sock;

                }
        }
}

4-1) HTTPS

openssl을 사용해 SSL을 발급 받겠습니다.

아래의 명령어를 입력해 Self Signed SSL Certificate를 발급받을 수 있습니다.

# create SSL directory
mkdir /etc/nginx/ssl

# create SSL certi & private key
openssl req -x509 -days 10 -nodes -newkey rsa:2048 -keyout /etc/nginx/ssl/self.key -out /etc/nginx/ssl/self.crt

이제 위에서 발급받은 SSL을 nginx에 적용해보겠습니다. nginx.conf를 아래와 같이 수정합니다.

nginx.conf

worker_processes auto;

events {
    worker_connections  1024;
}


http {
        include mime.types;

        server {
             # change https port;
                # listen 80;
                listen 443 ssl;
                root /sites/demo;
                index index.php index.html;

                # SSL certi
                ssl_certificate /etc/nginx/ssl/self.crt;
                # SSL key
                ssl_certificate_key /etc/nginx/ssl/self.key;

                location / {
                        try_files $uri $uri/ =404;
                }

                location ~\.php$ {
                        # Pass php requests to the php-fpm service (fastcgi)
                        include fastcgi.conf;
                        fastcgi_pass unix:/run/php/php7.10fpm.sock;

                }
        }
}

이제 nginx을 reload하면 아래와 같이 https로 접속할 수 있습니다. 아래의 경고는 Self Signed SSL을 사용했기 때문에 발생하는 경고로 저는 무시하고 진행하도록 하겠습니다.

4-2) HTTP/2

이제 HTTP/2를 적용해보도록 하겠습니다.

HTTP/2를 적용하기위해선 http_v2_module을 사용해야합니다. 먼저 아래의 명령어를 입력해 현재의 nginx configure를 확인하고 메모장에 저장해 놓습니다.

저는 기존 설치된 module에 ssl이 포함되어 있으므로 http2 모듈만 추가하도록 하겠습니다.

nginx -V

current module

--sbin-path=/usr/bin/nginx 
--conf-path=/etc/nginx/nginx.conf 
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log 
--with-pcre --pid-path=/var/run/nginx.pid 
--with-http_ssl_module 
--with-http_image_filter_module=dynamic 
--modules-path=/etc/nginx/modules

다음으로 source directory로 이동해 아래의 명령어로 http_v2 모듈을 확인합니다.

./configure --help | grep http_v2

이제 확인한 --with-http_v2_module을 앞서 메모장에 저장한 기존 nginx configure 맨뒤에 붙여넣습니다.

with http2 module

--sbin-path=/usr/bin/nginx 
--conf-path=/etc/nginx/nginx.conf 
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log 
--with-pcre --pid-path=/var/run/nginx.pid 
--with-http_ssl_module 
--with-http_image_filter_module=dynamic 
--modules-path=/etc/nginx/modules
--with-http_v2_module

다음으로 아래의 명령어를 순서대로 수행해 nginx을 update 합니다.

# add module
./configure [with http2 module]

# compile
make

# install
make install

# reload
nginx -s reload

마지막으로 nginx.conf를 열어 listen을 아래와 같이 변경합니다.

listen 443 ssl http2;

이제 모든 준비가 완료되었습니다. 😎

nginx를 reload하고 다시한번 https로 index.html을 요청하면 아래와 같이 HTTP/2가 적용된 것을 확인할 수 있습니다. 👏👏👏

5. Server Push

마지막으로 HTTP/2에서 사용가능한 Server Push에 대해 알아보겠습니다.

먼저 server push를 적용하기전의 상태를 살펴보면, index.html에 대한 data를 전송받은 다음에 index.html의 linked resource인 thumb.png와 style.css를 HTTP/2의 multiplex streaming을 통해 transfer 하고 있는 것을 확인할 수 있습니다.

이때 server push를 사용하면 index.html을 reponse할때 강제적으로 thumb.png와 style.css를 함께 return해 성능을 향상시킬 수 있습니다.

server push를 적용하기위해 nginx.conf 파일을 아래와 같이 수정합니다.

nginx.conf

worker_processes auto;

events {
    worker_connections  1024;
}


http {
        include mime.types;

        server {
             # change https port;
                # listen 80;
                listen 443 ssl http2;
                root /sites/demo;
                index index.php index.html;

                # SSL certi
                ssl_certificate /etc/nginx/ssl/self.crt;
                # SSL key
                ssl_certificate_key /etc/nginx/ssl/self.key;

                # server push
                location = /index.html {
                        http2_push /style.css;
                        http2_push /thumb.png;
                }


                location / {
                        try_files $uri $uri/ =404;
                }

                location ~\.php$ {
                        # Pass php requests to the php-fpm service (fastcgi)
                        include fastcgi.conf;
                        fastcgi_pass unix:/run/php/php7.10fpm.sock;

                }
        }
}

물론, 실제 환경에서는 위와 같이 server push를 구성하지 않습니다. 저는 테스트를 위해 index.html 요청시 style.css와 thumb.png를 함께 push하도록 변경했습니다.

저장후 nginx를 reload하면 아래와 같이 server push가 작동하는 것을 확인할 수 있습니다.

HTTP/2를 잘만 사용하면 상당한 수준의 성능향상을 꾀할 수 있을 것 같습니다. 👏👏👏


참고 자료 : https://www.udemy.com/course/nginx-fundamentals/


반응형

'Nginx' 카테고리의 다른 글

[Nginx] Rate Limiting  (0) 2020.08.31
[Nginx] HTTPS (SSL)  (0) 2020.08.31
[Nginx] FastCGI Cache  (0) 2020.08.31
[Nginx] Compressed Response with gzip  (0) 2020.08.31
[Nginx] Header & Expire  (0) 2020.08.31

댓글

Designed by JB FACTORY