전 세계 모든 HTTP 통신은 지구상의 컴퓨터와 네트워크 장비에서 널리 쓰이고 있는 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어집니다.
TCP는 HTTP에게 신뢰할 만한 통신 방식을 제공하기 때문에, 일단 커넥션이 맺어지면 클라이언트와 서버 컴퓨터 간에 주고받는 메시지들은 손실 혹은 손상되거나 충돌없이 순서가 바뀌지 않고 안전하게 전달됩니다.
위의 그림은 웹 브라우저가 TCP 커넥션을 통해서 웹서버에 요청을 보내는 과정입니다.
(1) 웹 브라우저가 URL의 호스트 명으로부터 76.76.21.61:443이라는 IP주소와 포트 정보를 얻습니다.
(2) 웹 브라우저가 76.76.21.61의 443포트에 TCP 커넥션을 생성합니다.
(3) 웹 브라우저가 서버로 HTTP 요청을 합니다.
(4) 서버가 웹 브라우저로 HTTP 응답을 합니다.
(5) 웹 브라우저가 TCP 커넥션을 끊습니다.
1.1 TCP 전송
HTTP가 메시지를 전송하고자 할 경우, 현재 연결되어 있는 TCP 커넥션을 통해서 메시지 데이터의 내용을 순서대로 보냅니다.
TCP 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷(혹은 IP 데이터그램)라고 불리는 봉투에 담아서 인터넷을 통해 데이터를 전달합니다.
각 TCP 세그먼트는 하나의 IP 주소에서 다른 IP 주로로 IP 패킷에 담겨 전달됩니다.
위의 그림은 IP 패킷의 구조입니다.
IP 패킷은 IP 패킷 헤더, TCP 세그먼트 헤더, TCP 데이터 스트림 덩어리로 나눌 수 있는데,
IP 패킷 헤더는 발산지와 목적 IP 주소, 크기, 기타 플래그를 가집니다.
TCP 세그먼트 헤더는 TCP 포트 번호, TCP 제어 플래그, 그리고 데이터의 순서와 무결성을 검사하기 위해 사용되는 숫자 값을 포함합니다.
※ IP 패킷의 구성 요소의 자세한 내용을 보고 싶으신 분은 구글에 구성 요소에 대해 검색하시면 쉽게 알 수 있습니다.
1.2 TCP 커넥션 유지
TCP는 포트 번호를 통해 여러 커넥션을 가질 수 있습니다.
TCP 커넥션은 다음과 같이 네 가지 값으로 식별합니다.
<발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트>
이 네 가지 값으로 유일한 커넥션을 생성합니다.
물론 유일한 커넥션이지만 다른 커넥션과 수신지 IP만 같거나 등 일부는 같을 수 있습니다.
1.3 TCP 소켓 프로그래밍
네트워크에서의 소켓은 데이터를 내보내거나 혹은 데이터를 받기 위한 실제적인 창구 역할을 합니다.
TCP 소켓 프로그래밍은 TCP 커넥션이 연결된 클라이언트과 서버의 소켓을 통한 상호작용을 위한 프로그래밍이라 할 수 있습니다.
위 그림은 서버와 클라이언트가 TCP 소켓 인터페이스를 사용하여 상호작용하는 방법입니다.
2. TCP의 성능
HTTP는 TCP 바로 위의 있는 계층이기 때문에 HTTP 트랜잭션의 성능은 그 아래 계층인 TCP 성능에 영향을 받습니다.
2.1 HTTP 트랜잭션 지연
트랜잭션을 처리하는 시간은 DNS를 찾고 TCP 커넥션을 설정하고 요청을 전송하고 응답 받는 시간에 비하면 상당히 짧습니다.
그렇기 때문에 대부분의 HTTP 지연은 TCP 네트워크 지연 때문에 발생합니다.
TCP 네트워크 지연은 하드웨어의 성능, 네트워크와 서버의 전송 속도, 요청과 응답 메시지의 크기, 클라이언트와 서버 간의 거리에 따라 크게 달라집니다.
물론 TCP 프로토콜의 기술적인 복잡성도 지연에 큰 영향을 줍니다.
2.2 TCP 커넥션 핸드셰이크 지연
핸드셰이크는 TCP의 신뢰성있는 통신 연결과 종료를 위한 통신 방법입니다.
핸드셰이크 종류에는 3-way handshake와 4-way handshake가 있습니다.
3-way handshake를 기준으로 간단히 설명드리자면,
클라이언트가 커넥션 생성 요청을 서버에 보내고
서버가 요청이 받아들여졌음을 클라이언트에 보내고
클라이언트가 커넥션이 연결됐음을 서버에게 보내는 것입니다. 클라이언트는 이때 데이터를 함께 보낼 수 있습니다.
어떤 데이터를 전송하든 새로운 TCP 커넥션을 열 때면, TCP 커넥션 핸드셰이크를 하게 됩니다.
그렇게 때문에 작은 크기의 데이터 전송에 커넥션이 사용된다면 HTTP 성능을 크게 저하시킬 수 있습니다.
2.3 TCP 느린 시작
TCP 커넥션은 시간이 지나면서 자체적으로 튜닝되어서 처음에는 커넥션의 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 속도 제한을 높여나갑니다.
이렇게 조율하는 것을 TCP 느린 시작이라고 합니다.
이는 인터넷의 급작스러운 부하와 혼잡을 방지하는데 쓰입니다.
2.4 TIME_WAIT
이전 커넥션과 관련된 패킷이 같은 주소와 포트 번호를 가지는 새로운 커넥션에 삽입되는 문제를 방지하기 위해 2분 정도 이내에 같은 주소와 포트 번호를 가지는 커넥션을 생성되는 것을 막아줍니다.
※ 2분은 보통 세그먼트의 최대 생명주기의 두 배 정도이며, 2MSL이라 불립니다.
예를 들어, 발신지 IP 주소와 포트, 수신지의 IP가 고정 되어있고 수신지의 포트만 변경할 수 있다고 하면,
수신지의 포트는 제한되어 있기 때문에 TIME_WAIT 상태에 들어가는 포트가 생기는 속도보다 트랜잭션 처리 속도가 느리다면 TIME_WAIT 포트 고갈이 발생합니다.
2.5 순차적인 트랜잭션 처리
브라우저가 어떤 페이지를 보여주기 위해 한 개의 HTML을 받기 위한 1개의 HTTP 트랜잭션과 세 개의 이미지를 받기 위한 3개의 HTTP 트랜잭션이 필요할 때, 이를 순차적으로 처리한다면, 각 트랜잭션이 새로운 커넥션을 맺는데 발생하는 시간과 함께 느린 시작 지연이 발생할 것입니다.
※ 이 외에도 네트워크 효율 관련해서 네이글 알고리즘, 확인응답 지연 알고리즘라는 것도 있습니다. 궁금하시다면 검색!
3. HTTP 커넥션 관리
커넥션 관리를 잘한다면 TCP 성능이 향상될 수 있습니다.
3.1 Connection 헤더
HTTP는 클라이언트와 서버 사이에 프락시 서버, 캐시 서버 등과 같은 중개 서버가 놓이는 것을 허락합니다.
HTTP 메시지는 클라이언트에서 서버까지 중개 서버들을 하나하나 거치면서 전달됩니다.
두 인접한 HTTP 애플리케이션이 현재 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있습니다.
이를 위해 전송자가 특정 커넥션에만 해당되는 옵션을 지정하게 해주는 것이 Connection 헤더입니다.
예를 들어 서버에 프락시 서버로 HTTP 메시지를 보낼 때, 헤더에 Connection: meter, close, bill-my-credit-card (Meter 헤더가 존재)가 있다고하면, meter 헤더를 다른 커넥션으로 전달하면 안되고 bill-my-credit-card 옵션을 적용할 것이며, 이 트랜잭션이 끝나면 커넥션이 끊길 것임을 의미합니다.
3.2 병렬 커넥션
클라이언트의 인터넷 대역폭을 한 개의 커넥션을 다 써버리는 것이 아니라면 남은 대역폭을 사용할 수 있습니다.
그렇기에 클라이언트가 여러 개의 커넥션을 한번에 맺을 수 있고, 이를 통해 여러개의 HTTP 트랜잭션을 병렬로 처리할 수 있습니다.
※ 병렬 커넥션에서 각 커넥션 사이에는 소프트웨어와 관련된 지연이 짧게 발생합니다.
병렬 커넥션이 일반적으로 더 빠르기는 하지만, 항상 그렇지는 않습니다.
예를 들어, 네트워크 대역폭이 좁을 때 각 커넥션에서 데이터를 전송받는 것은 느리기 때문에 성능상의 장점은 거의 없어집니다.
또한 다수의 커넥션은 메모리를 많이 소모하고 자체적인 성능 문제를 발생시킵니다.
예를 들어, 한 서버에 각 사용자가 많은 커넥션을 맺는다면 서버에 과부하가 걸리기 때문에 서버의 성능을 크게 저하시킵니다.
3.3 지속 커넥션
웹 클라이언트는 보통 같은 사이트에 여러 개의 커넥션을 맺습니다.
예를 들어 웹페이지에 첨부된 이미지들은 대부분은 같은 웹 사이트에 있고, 상당 수의 하이퍼링크도 같은 사이트를 가리킵니다.
따라서 서버에 HTTP 요청을 하기 시작한 애플리케이션은 웹페이지 내의 이미지 등을 가져오기 위해서 그 서버에 또 요청하게 될 것입니다.