커넥션을 생성하기 위해 3WAY 핸드쉐이크 과정을 거치는데, 요청 마다 TCP 구성을 해야 하므로 아주 큰 데이터를 받는 경우가 아니라면 지연을 발생 시킨다.
IP 패킷
TCP는 성공적인 데이터 전송을 보장하기 위해 TCP 세그먼트의 순번과 체크썸 확인을 통해 자체적인 확인 체계를 가진다.
각 세그먼트 수신자는 세그먼트를 온전히 받으면 작은 확인응답 패킷을 송신자에게 반환한다. 만약 송신자가 특정 시간 안에 확인응답 메시지를 받지 못하면 패킷이 파기되었거나 오류가 있는 것으로 판단하고, 데이터를 다시 전송한다.
확인응답은 그 크기가 작아서, TCP는 같은 방향으로 송출되는 데이터 패킷에 확인응답을 편승 시킨다. TCP는 송출 데이터 패킷과 확인응답을 하나로 묶음으로써 네트워크를 좀 더 효율적으로 사용한다.
송출할 확인응답을 특정 시간 동안 버퍼에 저장해 두고, 확인응답을 편승시키기 위한 송출 데이터 패킷을 찾는다. 만약 송출 데이터 패킷을 찾지 못하면, 확인응답은 별도 패킷을 만들어 전송된다.
안타깝게도 송출될 패킷이 많지 않아, 위의 확인응답 지연의 알고리즘이 지연을 발생 시킨다.
TCP 커넥션은 시간이 지나면서 자체적으로 튜닝되어서 처음에는 커넥션의 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라 속도 제한을 점점 높여 나간다. 이를 TCP 느린 시작이라고 부른다.
느린 시작을 하는 이유는 급작스러운 부하와 혼잡을 방지하는 데 쓰인다.
TCP 느린 시작은 TCP가 한 번에 전송할 수 있는 패킷의 수를 제한하고, 패킷이 성공적으로 전달되는 각 시점(확인응답을 받는 시점) 에 추가로 2개의 패킷을 더 전송할 수 있는 권한을 얻는다.
이 기능 때문에 새로운 커넥션은 이미 어느 정도 데이터를 주고받은 튜닝된 커넥션보다 느리다.
전송해야될 데이터가 있는데, 상대방의 윈도우 크기(전송 받을 수 있는 크기)가 매우 작은 경우. 내가 의도한 바는 아니지만 보낼 수 있는 패킷의 크기 자체가 작기 때문에 따로 지연 설정을 하지 않으면, 작은 크기의 패킷이 만들어질 수 밖에 없다.
보낼 수 있는 데이터를 바로 패킷으로 만들지 않고, 가능한 모아서 더 큰 패킷으로 만들어 한번에 보내면 이런 문제는 발생하지 않을 것이다. 네이글 알고리즘은 이 대안을 실제로 구현한 네트워크 전송 알고리즘이다.
네이글 알고리즘은 네트워크 효율을 위해서, 패킷을 전송하기 전에 많은 양의 TCP 데이터를 한 개의 덩어리로 합친다.
세그먼트가 최대 크기 (패킷의 최대 크기는 LAN 상에서 1500바이트)가 되지 않으면 전송을 하지 않는다.
다만 다른 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다.
다른 패킷들이 아직 전송 중이면, 데이터는 버퍼에 저장된다. 전송되고 나서 확인응답을 기다리던 패킷이 확인응답을 받았거나 전송하기 충분할 만큼의 패킷이 쌓였을 때, 버퍼에 저장되어 있던 데이터가 전송된다.
TCP_NODELAY 파라미터 값을 설정하여 네이글 알고리즘을 비활성화 하기도 한다. 단 작은 크기의 패킷이 너무 많이 생기지 않도록, 큰 크기의 데이터 덩어리를 만들어야 한다.
TCP 커넥션의 종단에서 TCP 커넥션을 끊으면, 종단에서는 커넥션의 IP 주소와 포트 번호를 메모리의 작은 영역(control block)에 기록해 놓는다.
이 정보는 같은 주소와 포트 번호를 사용하는 새로운 TCP 커넥션이 일정 시간 동안에는 생성되지 않게 하기 위한 것으로, 보통 세그먼트의 최대 생명주기에 두 배 정도(2MSL, 2min정도)의 시간 동안만 유지한다.
특정 커넥션이 생성되고 닫힌 다음, 그와 같은 IP 주소와 포트 번호를 가지는 커넥션이 2분 이내에 또 생성되는 것을 막아준다.
현대의 빠른 라우터들 덕분에 커넥션이 닫힌 후에 중복되는 패킷이 생기는 경우는 거의 없어졌다.
단 성능측정을 할때는 다르다. 그 서버에 접속하여 부하를 발생시킬 컴퓨터의 수가 적기 때문이다.
<발신지 IP 주소, 발신지 포트, 목적지 IP 주소, 목적지 포트>
가 있을 때 사용할 수 있는 발신지 포트의 수는 보통 65,535개니 6만개라고 봤을 때 2MSL (120초로 가정) 했을 때 60000 / 120 = 500으로 커넥션이 제한된다.
즉 서버가 초당 500개 이상의 트랜잭션을 처리할 만큼 빠르지 않다면, TIME_WAIT 포트 고갈을 일어나지 않는다.
이러한 문제를 해결하기 위해, 부하를 생성하는 장비를 더 많이 사용하거나 클라이언트와 서버가 더 많은 커넥션을 맺을 수 있도록, 여러 개의 가상 IP 주소를 쓸 수도 있다.