HTTP/2

천영석·2021년 9월 27일
0

오늘 http/2를 도입했다. 도입하는 것 자체는 쉬웠다. nginx가 기본적으로 http/2를 지원하기 때문에 ssl을 적용해 둔 상태였던 우리의 프로젝트에는 http2 5글자만 작성하면 끝났다. 도입한 과정보다는 왜 도입하게 되었고, 어떤 경험을 했는지 작성해 보려고 한다.

지금까지 http/2는 최신 브라우저에서만 작동한다는 편견이 있었다. http/2를 지원하지 않는 구형 브라우저에서는 동작하지 않을 것이라고 생각했다. 하지만 지원하는 브라우저 범위도 생각보다 넓고, http/2를 지원하지 않는 브라우저에서는 알아서 http/1.1로 응답을 한다고 한다.(nginx와 cloudfront 모두 가능) 아래의 지원 범위를 확인해 보면 사실 구형 브라우저는 신경 쓰지 않아도 될 정도이다. 이제는 http/2 도입을 안 할 이유가 없게 되었다.

출처: Can I Use

http/2를 도입하기 전에 http/1.1의 문제점부터 알아봤다. http/1.1은 하나의 커넥션에 하나의 요청과 응답을 맺을 수 있다. 그리고 1 -> 2 -> 3으로 요청을 했으면 응답도 1 -> 2 -> 3 순서로 받을 수 있기 때문에, 1에서 지연이 생겼다면 2, 3도 모두 늦게 받을 수 있다. 지연이 생기는 것이다. 이러한 문제점이 있다는 것을 공부했고, 성능에 굉장히 좋지 않겠다는 생각을 하며 네트워크 탭을 열어봤다.

오잉? http/1.1을 살펴보면 분명 위에서부터 아래대로 워터폴이 계단 모양으로 생성될 줄 알았는데 뭔가 병렬적으로 되는 것처럼 보였다. 공부한 것과 실제로 확인한 것이 다른 것이다. (여기에서 cloudfront는 기본 값으로 http2가 되고 있는 것도 확인했다.)

이 이유를 찾기 위해 검색을 하다가 keep-alive, 파이프라이닝에 대해 공부를 하게 되었다.
keep-alive는 예전에도 작성한 적이 있다. 우선 mdn에서는 해당 기술이 표준이 아니기 때문에 사용하지 않을 것을 권장하는 것으로 보인다. keep-alive보다는 http/2를 사용하는 것을 권장한다.

출처: mdn

간단하게 요약하면 tcp에서는 신뢰성을 위해 3way-handshake가 발생하는데, 이것이 요청할 때마다 발생하기 때문에 요청해야 할 컨텐츠가 많은 요즘 시대에서는 불필요한 요청을 추가적으로 하는 것이다. 한번 3way-handshake를 통해 인증받은 후에 커넥션을 유지하고 다른 자원들을 받는 것이 말로만 들어도 더 좋아 보인다. 그것을 가능하게 해주는 것이 keep-alive이다. 하지만 http/1.x의 특성상 앞선 요청에 지연됐을 경우에는 뒤의 요청도 지연되기 때문에 큰 해결책이 되지는 못한 것 같다. 게다가 유휴 시간이 발생하는 경우에도 keep-alive로 인해 커넥션이 유지되고 있다면 문제가 될 수 있다.

즉, keep-alive로 인해 위의 그림처럼 병렬적으로 실행되는 것은 아닌 것 같았다.

이번에는 파이프라이닝에 대해 알아봤다. 파이프라이닝은 요청 -> 응답, 요청 -> 응답으로 응답 후에 요청을 보내던 것에서 지연 시간을 줄이기 위해 하나의 TCP에 보내야 할 요청을 모두 미리 보내놓고, 응답을 기다리는 것이다.

출처: mdn

이것도 좋은 방법인 것 같지만 엄청난 해결책은 아니다. 하나의 응답이라도 지연되면 그 뒤의 응답까지 지연되는 것을 똑같기 때문이다. mdn에 따르면 여러 가지 버그가 있고, 성능 향상도 미미하다고 한다. 그래서 최신 브라우저에서도 해당 옵션이 기본 값으로 설정되어 있지 않다고 한다. (그냥 http/2 쓰라고 하는 것 같다.)

결국 keep-alive, 파이프라이닝 모두 위의 그림처럼 병렬적으로 실행되는 이유는 아니었다. 위의 그림은 분명 먼저 보낸 요청보다 먼저 응답이 오는 자원들이 보이기 때문이다.

그러던 와중에 한 블로그를 발견했다. http/2 알아보기 - 1편

http/1.1은 성능 향상을 위해 커넥션을 6~8개를 두어 자원을 가져온다는 것이다. 그래서 커넥션Id 순으로 정렬해서 확인해 봤다.

이제 명확하게 보였다. 커넥션을 여러 개 만들어서 요청과 응답을 병렬적으로 하고 있었고, 커넥션 Id가 같다면 http/1.x의 특징을 그대로 가지고 있었다. 첫 번째 두 번째 요청과 응답을 확인해 보면 같은 커넥션 Id(179621)를 가지고 있고, 첫 번째 응답이 왔을 때 두 번째 요청을 시작하는 것을 확인할 수 있다.

위의 블로그 덕분에 궁금증이 겨우 해결되었다.(감사합니다!!)

이제 위의 그림과 같은 워터폴을 해결하면서 하나의 커넥션으로 병렬적으로 요청을 보낼 수 있고, 순서에 상관없이 먼저 완료된 대로 응답을 줄 수 있는 http/2를 사용할 이유가 생겼다.
http/1.1 vs http/2 애니메이션 비교

주요한 http/2의 특징을 짚고 넘어가자면
1. 멀티플랙싱을 통해 하나의 TCP 커넥션으로 거의 무한대의 요청을 병렬적으로 처리할 수 있다.
2. request, response 헤더를 압축하고, 중복된 헤더는 요청하지 않는 방식으로 용량을 크게 줄였다.
3. 우선순위를 두어 원하는 자원을 먼저 받을 수 있도록 설정할 수 있다.
4. 서버 푸쉬를 통해 필요한 자원을 요청하기 전에 미리 보낼 수 있다.
정도로 요약할 수 있을 것 같다.
출처: google developers

우리는 이러한 이점을 누리기 위해 http/2를 도입했고, 서버 푸쉬는 하지 않은 상태이다. 이유는 js 파일은 모두 캐시가 되는 상태이기 때문에 캐시가 되어있지 않은 경우에만 응답하면 되기 때문이다. 아직 서버 푸쉬를 할 때 브라우저 캐시까지 확인해서 응답을 하는지는 확인하지 못해서 사용하지 않았다. 아마 이것까지 확인하는 것은 불가능하지 않을까??

마지막으로 적용된 모습은 아래와 같다.

profile
느려도 꾸준히 발전하려고 노력하는 사람입니다.

0개의 댓글