1:21 · TCP · retransmission · RTO · metrics

사라진 패킷 하나가 전부를 멈춘다

TCP가 잃어버린 세그먼트를 다시 보내는 두 가지 방식(Fast Retransmit, RTO)과, 재전송 하나가 같은 연결의 뒤따르는 데이터까지 멈추게 하는 Head-of-Line 블로킹을 보여준다. 작은 패킷이 띄엄띄엄 오가는 게임 트래픽은 RTO로 빠지기 쉬워 수백 ms 정지가 생긴다. 같은 사건이 클라, 서버, 인프라에서 각각 어떤 지표로 보이는지와 확인 명령, 완화 방법까지 정리한다.

01잃으면 다시 보낸다

TCP는 모든 바이트가 순서대로, 반드시 도착해야 다음으로 넘어간다 · ▶ 이 장면 보기

위쪽 선이 송신측(서버), 아래쪽 선이 수신측(클라)이다. Seq 1, Seq 2는 정상 도착하고 각각 ACK 2, ACK 3이 돌아간다. Seq 3은 중간에서 사라진다.

이후 Seq 4, 5, 6이 도착해도 수신측은 3번을 아직 못 받았으므로 계속 "3번이 필요하다"는 ACK를 반복해서 보낸다. 이것이 Dup ACK다. 송신측은 같은 ACK가 3번 중복되면 타이머를 기다리지 않고 Seq 3을 바로 다시 보낸다(Fast Retransmit). 재전송이 도착하면 수신측은 4~6번까지 한 번에 확인하고 ACK 7을 보낸다.

TCP는 모든 바이트가 순서대로, 반드시 도착해야 다음으로 넘어간다. 재전송은 이 보장을 지키기 위한 동작이다.

02언제 생기나

원인은 달라도 결과는 같다: ACK가 안 오면 다시 보낸다 · ▶ 이 장면 보기

손실 원인은 달라도 결과는 같다. ACK가 오지 않으면 송신측은 다시 보낸다. 화면에는 네 가지 원인이 나온다.

03두 가지 재전송

Fast Retransmit은 짧고, RTO 타임아웃은 길다 · ▶ 이 장면 보기

위 줄은 패킷이 20ms 간격으로 촘촘하게 나가는 경우다. 100ms 지점의 패킷이 손실되면 바로 뒤 패킷들이 Dup ACK 3개를 만들고, 송신측이 즉시 재전송한다. 정지는 약 100ms, 대략 1 RTT 수준이다.

아래 줄은 패킷이 띄엄띄엄 나가는 경우다. 손실 뒤 다음 패킷이 RTO보다 늦게 나가므로 손실을 알려 줄 ACK가 없다. 송신측은 RTO 타이머를 기다린다. 첫 재전송은 RTO 200ms 뒤에 나가지만 이것도 손실되고, 타이머가 2배로 늘어 RTO 400ms 뒤에야 재전송이 성공한다. 이 예에서 정지는 620ms다.

게임 트래픽은 작고 간격이 넓어서, 손실 뒤 다음 패킷이 RTO 전에 나가지 않으면 RTO로 빠진다. 리눅스에서 RTO 최솟값은 200ms이고 실패할 때마다 200, 400, 800, 1600ms로 두 배씩 늘어난다.

재전송 뒤에는 혼잡 윈도우(cwnd)도 줄어든다. 영상은 Fast Retransmit이면 줄이고(Reno는 절반, 리눅스 기본 CUBIC은 0.7배), RTO면 1부터 Slow Start로 다시 시작한다고 설명하며, 그만큼 처리량이 급감한다.

04Head-of-Line 블로킹

하나가 빠지면 뒤에 도착한 것까지 전부 기다린다 · ▶ 이 장면 보기

클라 커널 수신 버퍼에 Seq 4~Seq 8은 이미 도착해 있지만 Seq 3 칸은 비어 있다. 앱은 3번부터 순서대로만 읽을 수 있으므로, 뒤 데이터는 도착하고도 버퍼에서 기다린다. 재전송된 3번이 들어오는 순간 쌓인 데이터가 한꺼번에 게임 앱의 recv()로 넘어간다.

아래 타임라인은 앱 입장에서 본 메시지 도착이다. 일정 간격으로 오던 메시지가 한동안 하나도 오지 않다가, 재전송 시점에 여러 개가 몰려 들어온다.

TCP 연결 하나는 한 줄로 선 대기열과 같아서, 앞의 하나가 빠지면 같은 줄의 메시지는 전부 기다린다.

05클라 · 서버 · 인프라에 보이는 것

같은 사건, 세 곳의 다른 증상과 지표 · ▶ 이 장면 보기

같은 손실 사건이 세 곳에서 다른 모습으로 보인다. 각 열 위의 그래프는 사건 동안 대표 지표가 튀는 모양을 그린 것이다.

06확인하고 줄이기

지표로 확인하고, 구조로 피한다 · ▶ 이 장면 보기

왼쪽은 확인 방법이다.

재전송률 기준은 예시로 0.5% 미만이면 정상, 2%를 넘으면 조사 대상으로 제시된다.

오른쪽은 줄이는 방법이다.

작은 패킷을 보내는 소켓에 Nagle이 켜져 있으면 ACK를 못 받은 세그먼트가 하나뿐이라 dup ACK가 생기지 않고, 손실은 빠른 재전송 대신 RTO로만 복구됩니다. 이 관계는 Nagle과 TCP_NODELAY 영상에서 다룹니다.

이 영상에 나온 용어는 용어집에 정리했다.