Search
🌐

TCP 성능

 이전 글 : TCP 오류복구
 다음 글 : TCP keep-alive
Latency가 높은 곳을 찾아보자
TCP의 신뢰성을 보장하기 위한 기능들이 성능과 Trade off되기도 한다. 이에 이번 포스팅에서는 성능을 보완하기 위한 몇가지 조언을 정리해본다.
TCP 네트워크 지연은 하드웨어의 성능, 네트워크와 서버간의 전송속도, 요청과 응답 메시지의 크기, 클라이언트와 서버간의 거리에 따라 달라진다.

1. TCP Connection handshake 지연

어떤 데이터를 전송하든 새로운 TCP connection을 열 때면, TCP 소프트웨어는 connection을 맺기 위한 조건을 맞추기 위해 연속으로 IP packet을 교환한다. 작은 크기의 데이터 전송에 이런 connection이 사용된다면 HTTP 성능을 저하시킬 수 있다.

2. ACK 지연

각 TCP 세그먼트는 순번과 데이터 무결성 체크섬을 가진다. 각 세그먼트의 수신자는 세그먼트를 온전히 받으면 작은 ACK 패킷을 송신자에게 반환한다. 만약 송신자가 특정 시간 안에 ACK 메시지를 받지 못하면 패킷이 파기되었거나 오류가 있는 것으로 판단하고 데이터를 다시 전송한다. ACK는 그 크기가 작기 때문에, TCP는 같은 방향으로 송출되는 데이터 패킷에 ACK를 편승(piggyback)시킨다. (TCP는 송출데이터 패킷과 ACK를 하나로 묶음으로써 네트워크를 좀 더 효율적으로 사용한다.)
ACK 지연은 송출할 ACK를 특정 시간동안 (보통 0.1~0.2초) 버퍼에 저장해두고, ACK를 편승시키기 위한 송출 데이터 패킷을 찾는다. 만약 일정 시간 안에 송출 데이터 패킷을 찾지 못하면 ACK는 별도 패킷을 만들어 전송된다. (HTTP는 오히려 지연의 원인이 되기도 함)

3. Slow start

TCP의 Slow start는 TCP가 한번에 전송할 수 있는 패킷의 수를 제한한다. 이에 Slow start는 최대로 사용할 수 있는 대역폭에 제한을 둠으로써 용량이 작은 데이터를 전송하는 데에는 부작용으로 다가온다. 따라서 새로운 Connection을 생성하기 보다 이미 어느정도 데이터를 주고받은 '튜닝'된 Connection이 빠르기에 HTTP에는 이미 존재하는 Connection을 재사용하는 기능이 있다.

4. Nagle 알고리즘과 TCP_NODELAY

TCP 세그먼트는 40바이트 상당의 플래그와 헤더를 포함하여 전송하기 때문에, TCP가 작은 크기의 데이터를 포함한 많은 수의 패킷을 전송한다면 네트워크 성능은 크게 떨어진다. Nagle 알고리즘은 세그먼트가 최대 크기(LAN상 1500, WAN상 수백 바이트)가 되지 않으면 전송을 하지 않는다. 다만 다른 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다. 전송하기 충분할 만큼의 패킷이 쌓였을 때 버퍼에 저장되어 있던 데이터가 전송된다. 이 경우 크기가 작은 HTTP 메시지는 지연된다. ACK 지연과 함께 고려하면 지연 시간은 더욱 늘어난다. 이에 TCP_NODELAY 설정을 비활성화하기도 한다.

5. TIME_WAIT의 누적과 포트 고갈

TIME_WAIT 포트 고갈은 성능 측정시에 심각한 성능 저하를 발생시키지만, 보통 실제 상황에서는 문제를 발생시키지 않는다. TCP 커넥션을 끊으면 종단에서는 커넥션의 IP 주소와 포트번호를 메모리의 작은 제어영역에 기록해 놓는다. 이 정보는 같은 주소와 포트번호를 사용하는 새로운 TCP 커넥션이 일정시간 동안에는 생성되지 않게 하기 위한 것으로, 보통 세그먼트의 최대 생명주기에 두 배정도(2MSL)의 시간동안만 유지된다. 가령, 발신지 포트의 수를 60,000개정도라 가정하고 2MSL(120초라 가정)동안 커넥션이 재사용될 수 없으므로 초당 500개(60,000 / 120 = 500)로 커넥션이 제한된다. 서버가 초당 500개 이상의 트랜잭션을 처리할만큼 빠르지 않다면 TIME_WAIT 포트고갈은 일어나지 않는다. 포트고갈 문제를 겪지 않더라도 커넥션을 너무 많이 맺거나 대기 상태로 있는 제어 블록이 너무 많아지는 상황은 주의해야 한다.

6. Head-of-Line (HOL) 블로킹

TCP는 고유의 시퀀스 번호를 가지며 수신자에게 주어진 순서대로 전달되어야 한다. 이에 패킷 하나가 소실되면 다른 모든 패킷들은 소실된 패킷이 재전송될 때까지 수신자 쪽 TCP 버퍼에서 대기해야만 한다. 이를 TCP HOL 블로킹이라 한다. HOL 블로킹의 장점은, 애플리케이션이 패킷의 재배치나 재조합에 관여할 필요가 없어 애플리케이션의 코드 자체가 훨씬 간단해진다는 것이다. 하지만 단점은 도착시간이 들쭉날쭉해서 latency를 예측하기 어렵다는 것이다(jitter) latency나 jitter에 예민한 애플리케이션의 경우 UDP를 사용하는 것이 더 좋다.

7. 추가적으로..

서버 커널을 최신버전으로 업그레이드하라
cwnd size는 10으로 설정하라
유휴 상태(idle) 후 slow start를 비활성화하면 수명이 길고 한번에 데이터 전송이 많은 TCP 커넥션의 성능을 높일 수 있다.
window scaling을 활성화하라
 이전 글 : TCP 오류복구
 다음 글 : TCP keep-alive