HTTP 요청과 응답 시, 다수의 TCP 연결을 줄이기 위한 방법
HTTP1.0 버전 발표 이후, 클라이언트와 서버간 요청과 응답을 어떻게 하면 좀 더 빨리 할 수 있을지에 대한 연구가 이루어졌다. 대표적으로 Persistent Connection, Pipelining 기법이 HTTP1.X 시대에 이를 위해 만들어진 방법이다.
HTTP 통신을 통해 여러 오브젝트를 요청 및 응답해야 하는 경우, HTTP1.0 초기에는 요청때마다 TCP 연결을 3-Way handshake 방식으로 맺어야했다. 3-Way handshake 는 아래 그림과 같이 SYN , SYN-ACK , ACK 로 이루어진다.
5개의 오브젝트를 가진 하나의 웹 페이지가 있다면 클라이언트와 서버 사이에는 5번의 3-Way handshake 과정을 통해 TCP 연결을 맺고 끊는 반복이 필요했던 것이다.
웹의 초장기에는 웹을 통해 전달해야 하는 사이트의 콘텐트 수가 그리 많지 않았기 때문에 다수의 TCP 연결 사용으로 인한 부담은 그리 크지 않았으나, 웹 사이트의 콘텐트 (특히 이미지 등의 멀티미디어)가 늘어나면서 TCP 연결의 재사용이 필요하게 되었다. 이때 나온 기술이 Persistent Connection 기술이다.(keep-alive 혹은 connection re-use라는 표현도 사용한다)
HTTP1.0 기반에서 Persistent Connection(연결 지속)을 사용을 원하고, 이를 지원하는 클라이언트는 다음과 같이 서버에게 HTTP요청 시, 요청 message내 헤더에 다음 헤더를 추가한다.
Connection: keep-alive
Persistent 커넥션을 지원하는 서버는 클라이언트의 요청을 수용하고 TCP 연결을 HTTP 응답이후에 끊지않고 계속 사용하겠다라는 약속으로 동일한 헤더를 HTTP 응답에 포함한다.
HTTP1.1에서는 굳이 Connection 헤더를 사용하지 않더라도, 모든 요청과 응답은 기본적으로 Persistent Connection를 지원하도록 되어서 필요없을 경우에만(HTTP 응답이 완료된 이후에 TCP 연결을 끊어야 하는 경우에만) 다음과 같이 Connection 헤더를 사용하였다.
다음 예제를 통해 이 부분을 자세히 알아보자.
curl -v -o out https://www.akamai.com/kr/ko/
... skipped ...
............
> GET /kr/ko/ HTTP/1.1
> User-Agent: curl/7.37.1
> Host: www.akamai.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Last-Modified: Thu, 22 Sep 2016 04:05:47 GMT
< Content-Type: text/html;charset=UTF-8
< Connection: keep-alive
예제를 보면 curl을 통해 특정 페이지 요청 시 클라이언트 입장에서는 별도의 Connection 헤더를 보내지 않았지만 HTTP1.1 통신이 이루어지면서 Connection: keep-alive 값을 응답 헤더내에 받았다. 즉 서버는 Persistent Connection을 지원하고 있으며 이를 사용하겠다는 의미를 클라이언트에게 전달한 것이다.
curl -v -o out https://www.akamai.com/kr/ko/ -H "Connection: Close"
... skipped ...
............
> GET /kr/ko/ HTTP/1.1
> User-Agent: curl/7.37.1
> Host: www.akamai.com
> Accept: */*
> Connection: Close
>
< HTTP/1.1 200 OK
... skipped ...
............
< Connection: close
두 번째 예제의 요청에는 요청헤더에 Persistent Connection을 사용하지 않겠다는 클라이언트의 의지(?)를 요청 헤더에 포함하였고, 서버는 이를 수락한 메시지를 응답 헤더에 보내왔다.
두 개의 예제를 통해 HTTP1.1에서는 Persistent Connection을 클라이언트와 서버가 기본적으로 지원하며, 필요 없을경우에만 Connection: Close 를 통해 사용하지 않을 수 있는 것을 알 수 있다.
Persistent Connection을 사용하지 않아야 하는 경우가 종종 있는데 서버에 연결된 모든 클라이언트의 TCP 연결이 계속 늘어나다보면, 서버의 자원이 고갈되어 더욱 많은 클라이언트의 접속에 대처할 수 없는 상황이 될수있는 시나리오가 발생할 수 있다. 따라서 클라이언트의 접속이 제일 잦은 메인 페이지와 같은 URL에서는 서버의 가용성을 고려하여 Persistent Connection 을 사용하지 말지를 고민해봐야 한다.
반대로 Persistent Connection을 사용하면서 얻을 수 있는 장점은 서버의 단일 시간내 TCP 연결의 수를 그만큼 적게함으로서 서버의 CPU나 메모리 자원을 절약할 수 있고, 네트워크 혼잡이나 지연의 경우의 수를 줄일 수 있다. 또한 Persistent Connection는 복수개의 HTTP 요청과 응답을 병렬적으로 동시에 처리하기 위한 HTTP Pipelining 기술을 사용하기 위해서는 꼭 지원되어야 한다.
HTTP/2 버전은 멀티플렉싱(Multiplexing) 기능으로 단일 TCP 연결을 통해(Persistent Connection in HTTP1.X), 다수의 HTTP 요청과 응답(HTTP Pipelining in HTTP1.1) 이 클라이언트와 서버사이에 응답 지연(HOL: Header of Line blocking) 없이 Stream형태로 주고 받을 수 있는 기술적 토대를 만들게 되었다. 따라서 HTTP/2를 사용한다면 Persistent Connection 에 대해 더 이상 고민할 필요가 없어지게 되었다. - What a wonderful HTTP/2 World!