크롬 확장 프로그램 만들기, GCM 알림 받기
HTTP의 버전 별 차이에 대해 알아보고 Ubuntu-Nginx에 HTTP/2를 적용해 봅니다.
2019-02-16
Explanation
오늘은 간단하게 HTTP의 버전 별 차이점에 대해 알아보고 실제로 Nginx서버에 HTTP/2를 적용해보려고 합니다.
그리고 글의 대부분의 정보가 다른 웹사이트와 블로그의 글을 읽고 이해한 부분이기에 조금 더 자세하고 확실한 정보는 아래의 참고한 글을 읽어보시는 것이 좋을 것 같습니다.
참고.
MDN – HTTP의 진화 (HTTP의 전체적인 설명)
I HATE FAT – (HTTP/1.0과 HTTP/1.1의 차이)
커피닉스 – (HTTP/1.0 – HTTP/1.1 의 Protocol Massage & Header 구성요소)
POPIT ‘심 천보’님의 글 – (HTTP/1.1과 HTTP/2의 설명)
Google Web Fundamentals – (HTTP/2 소개)
네트워크에 대한 지식이 많지 않아, 잘 모르는 내용을 막 적는 것보다는 개인적으로 그래도 사용하며 조금은 익숙해진 부분들 위주로 작상해 보려합니다.(글에 포함되지 않은 더 많고, 중요한 차이점 들이 있을 수 있습니다.)
HTTP의 초기 버전에는 버전 정보가 없었고 차후에 구분을 위해 0.9라고 불리게 되었다고 합니다. 아주 단순하게 GET 통신만 가능하고 이후에 버전에 존재하는 HTTP 헤더가 없기 때문에 전송은 HTML 문서만 가능하고 다른 유형은 전송할 수 없습니다. 또한 상태 혹은 오류 코드가 없기 때문에 문제의 상황시 해당 파일 내부에 문제에 대한 설명을 포함하여 보내졌다고 합니다.
HTTP/1.0 에서는 상태코드가 응답값 시작 부분에 포함되어 요청에 대한 성공과 실패를 바로 확인할 수 있게 되었습니다. 그리고 위에 언급하였던 HTTP 헤더가 요청과 응답 모두에 추가되어 프로토콜의 확상이 가능해지고 헤더의 ‘Content-Type’의 도움으로 HTML 파일 이외의 다른 문서들도 전송이 가능하게 되었습니다. 또한 메서드 POST, HEAD가 추가되었습니다.
(용어의 좁은 의미에서 공식적인 표준은 아니라고 합니다)
1 2 |
# html 요청 GET /mypage.html HTTP/1.0 |
1 2 3 4 |
# html 응답 200 OK ... Content-Type: text/html |
1 2 |
# gif 요청 GET /myimage.gif HTTP/1.0 |
1 2 3 4 |
# gif 응답 200 OK ... Content-Type: text/gif |
그 밖에 낯익은 헤더 중 HTTP/1.0에 추가된 헤더 값들은..
1 2 3 |
Content-Encoding : 리소스의 압축방식 (ex. gzip) Authorization : 사용자 인증정보 : 사용자 ID와 암호에 대한 암호화된 Base64 코드 (ex. Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ...) User-Agent: Mozilla/5.0 (Macintosh; Intel Mac...) |
HTTP/1.1은 HTTP의 첫번째 표준 버전입니다. 눈에 잘 보이는 추가점은 메서드에 OPTIONS, PUT, DELETE, TRACE 가 추가되었습니다. 그리고 헤더값도 몇가지 추가되었는데요, 역시 그 중에 조금 낯익은 부분들은 아래와 같습니다.
1 2 |
Via : 중계서버(프록시, 게이트웨이 등)의 지원 프로토이름.버전.호스트명 (ex. via: 1.1 123abc.cloudfront.net (CloudFront)) Accept : 클라이언트의 사용가능 미디어타입 (ex. application/json, text/plain, */*) |
그리고 HTTP/1.1 에서는 성능향상을 위해 바뀐 부분이 몇가지 있는데요. 깊이 있게 알고 있진 않지만 대략 이야기를 해보자면, 이전 HTTP/1.0에서의 통신은 예를 들어, 같은 요청하는 서버(클라이언트 서버)와 응답해 줄 서버(API 서버)가 10개의 API 통신을 한다고 하면 연결(커넥션)을 맺고 그다음 리소스를 주고 받고 둘의 연결을 끊고를 10번 반복하게 됩니다. 그런데 HTTP/1.1 에서는 일정시간 클라이언트 서버와 API서버간의 연결 정보를 기억하여 반복적으로 일어나는 통신에 연결의 맺고 끊음을 줄였습니다.
위의 이야기는 쉽고 간단한 이해를 위한 글로 실제와 차이가 있을 수 있습니다…
그리고 파이프라이닝이라는 것이 추가되었는데요 이 역시 간단하게 이야기를 하면, 여러개의 요청이 있을때 이전의 요청이 완전히 전송되기 전에 다음의 요청을 전송을 가능하게하여 레이턴시를 낮추었다고 합니다. 쉽게 이야기를 하면… 전송받는데 1초가 걸리는 이미지 파일 10개 요청한다 했을때, 이전에는 1초씩 10번 걸려서 10초가 걸렸는데, 파이프라이닝이라는 것을 통해서 0.8초 쯤 다음 이미지를 요청하도록 해서 총 8초면 된다. 뭐 이런 이야기 같습니다.
사실은 앞선 이야기는 이것을 적기 위환 과정이었던 거 같아요. 우선 HTTP/2는 2010년 전반기에 구글이 실험적인 SPDY 프로토콜을 구현해서 클라이언트와 서버 간의 데이터 교환을 대체할 수단을 실증했다고 합니다. 그리고 그것이 HTTP/2의 기초로서 기여했다고 합니다.(윾시 구글..)
HTTP/2 프로토콜은 HTTP/1.1 과 몇가지 근본적인 차이가 있는데요. 몇가지가 적혀있는데, 가장 핵심적인 부분은 HTTP/1.1이 텍스트 프로토콜이라면 HTTP/2는 이진 프로토콜이라는 점 같습니다.
물론, 왜 그게 핵심적인 부분인지는 모릅니다.. 뭐랄까.. 느낌적인 느낌?..
하지만, 대략적으로 추측을 해보자면, 텍스트 형태의 리소스는 바이너리 형태에 비해 당연히 효율이 나쁠 것 같아요. 텍스트는 사람이 이해하기 좋을 뿐 컴퓨터는 어짜피 결론적으로 바이너리 형태로 이해할태니까요. 간추리면 브라우저에서 데이터를 바이너리 값으로 변환하여 서버로 보내고 서버는 그 바이너리 값을 해석하여 처리하겠죠? ‘Google – Web Fundamentals’의 문서를 참고하면 아래와 같이 데이터를 바이너리 프레이밍 값으로 캡슐화하여 주고 받는 것 같습니다.
1 2 3 4 5 6 7 |
# HTTP 1.1 POST /upload HTTP/1.1 Host: www.example.org Content-Type: application/json COntent-Length: 15 ... {"msg": "hello"} |
1 2 3 |
# HTTP 2.0 HEADER frame DATA frame |
그리고 이러한 바이너리 프레이밍 구조가 이후에 나오게 될 HTTP2의 특징이나 장점에 기본이 되는 부분인 것 같습니다. 저의 지식이 얕기 때문에 프로토콜의 원리에 대해 이해하고 이야기하는 것은 어려울 것 같고 간단하게 특징을 적어보려합니다.
4-1. 요청 및 응답 다중화
HTTP/1.1 에서는 한번에 커넥션을 맺고 데이터를 요청하고 응답받고를 반복하는데요, HTTP/2에서는 스트림(stream)으로 한번의 커넥션으로 동시에 여러개의 데이터를 주고 받을 수 있습니다. 이렇게 하여 HTTP/1.x 에서의 이미지 스프라이트, 도메인 분할 같은 임시방편을 사용하지 않아도 됩니다.
4-2. 스트림 우선 순위
위와 같이 스트림의 프레임으로 다중화가 가능해짐과 동시에 클라이언트와 서버의 통신 순서를 위해 각 스트림에는 1~256 사이의 정수 가중치가 할당되어 스트림 처리 우선순위를 정합니다.
그런데 이게 우선 순위를 지정하여 이를 처리할 CPU, 메모리 및 기타 리소스의 할당을 제어하는 것일 뿐 특정 순서로 처리되도록 서버에 강요될 수 없다고 합니다.
HTTP도 TCP 위에서 돌아가는데… 이 부분은 좀 더 공부해야 이해할 수 있을 것 같습니다.
4-3. 헤더 압축
HTTP/1.x의 경우에는 가령 두개의 동일한 요청을 보낸다고 했을때, 두개의 헤더에 중복값이 존재해도 모두 전송하는데요, HTTP/2에서는 HPACK 압축형식을 사용해서 요청 및 응답 헤더 메타데이터를 압축하는데 이때 이 중복되는 헤더값을 색인값으로 처리해준다고 합니다.
그 밖에 몇가지 특징이 소개되어 있는데요. 아래 링크를 통해 확인해 보실 수 있습니다.
Google Web Fundamentals – (HTTP/2 소개)
이제 HTTP/2에 대해 좀 알아보았으니 직접 서버에 HTTP/2 설정을 해보도록 하겠습니다.
우선 현재 https://lab.falsy.me 사이트가 어떤 통신이 되고 있는지 확인해보겠습니다, 우선 터미널을 열고
1 2 3 4 5 |
$ curl -I https://lab.falsy.me HTTP/1.1 200 OK Server: nginx/1.14.0 (Ubuntu) ... |
이렇게 HTTP/1.1이 사용되고 있는 걸 확인 할 수 있습니다.
적용을 위해 조금 검색을 해보니 HTTPS 설정이 되어 있어야 하는 것 같아요. Let’s Encrypt를 이용해서 HTTPS 적용하는 방법은 아래의 링크를 참고하실 수 있습니다.
Let’s Encrypt로 https 설정하기
SSH로 우선 서버에 접속합니다.
1 |
$ ssh -p 1345(포트번호) falsy(사용자계정)@100.100.100.100(ip주소 또는 도메인) |
HTTP/2이 지원하지 않을때는 HTTP/1.x를 사용하여 통신하게 되는데요. 크롬은 ALPN을 사용하지 않으면 HTTP/1.x로만 통신을 한다고 합니다. 그리고 Open SSL은 1.0.2 버전부터 ALPN을 지원한다하네요.
그리하여 HTTP/2 적용을 위해서는 버전이 Nginx v1.9.5, Open SSL v1.0.2 이상이여야 한다고 합니다.
만약 위 버전보다 낮다면 업데이트 해주세요.
1 2 3 4 5 6 7 |
# Nginx 버전 확인 $ nginx -v # nginx version: nginx/1.14.0(Ubuntu) # Open SSL 버전 확인 $ openssl version # OpenSSL 1.1.0g 2 Nov 2017 |
제가 사용하는 버전은 모두 그 상위 버전이네요.
그리고 아래의 명령어로 현재 사용하는 도메인(또는 IP)가 ALPN을 사용하고 있는지 확인 할 수 있습니다.
아직 HTTP/2 설정 전 이여서 저는 No ALPN negoriated 가 출력되네요.
1 2 3 |
$ echo | openssl s_client -alpn h2 -connect lab.falsy.me:443 | grep ALPN #No ALPN negotiated |
다음으로 Nginx의 가상 호스트 설정을 해주어야 하는데요. 지금 보니.. 따로 가상 호스트 설정에 대한 글을 작성한 적이 없어서, 아래의 링크에서 6번을 조금 참고하실 수 있을 것 같습니다.
Nginx 가상호스트 설정
저는 falsy라는 이름으로 가상호스트 설정을 만들고 심볼 링크를 만들어서 사용하는데요. vi 에디터로 설정 파일을 열어줍니다.
1 |
$ vi /etc/nginx/sites-available/falsy |
그러면 저 같은 경우에는 아래와 같은데요..
1 2 3 4 5 6 7 |
server { listen 443 ssl; server_name lab.falsy.me; ... } |
위 부분을 아래와 같이 수정해줍니다.
1 2 3 4 5 6 7 |
server { listen 443 ssl http2; server_name lab.falsy.me; ... } |
그리고 :wq 명령어로 수정 저장해주시고 nginx를 재시작 합니다.
1 |
$ service nginx restart |
이렇게만 하면 끝! 생각보다 엄청 간단하네요. 진작 설정해줄 걸 그랬습니다…
이제 아까 ALPN이 사용되는지 한번 확인해볼까요?
1 2 3 |
$ echo | openssl s_client -alpn h2 -connect lab.falsy.me:443 | grep ALPN #ALPN protocol: h2 |
이렇게 ‘ALPN protocol: h2’ 뜨면 사용하고 있는 것 입니다.
그리고 이제 마지막으로 사이트가 HTTP/2로 통신하는 것으로 바뀌었는지 확인해 봅니다.
1 2 3 4 5 |
$ curl -I https://lab.falsy.me HTTP/2 200 OK Server: nginx/1.14.0 (Ubuntu) ... |
짜잔~
참고.
https://github.com/wonism/TIL/blob/master/back-end/nginx/http2.md