TCP 처리량은 단순히 링크 속도 하나로 정해지지 않고, 송신자가 아직 확인받지 않은 데이터를 얼마나 보낼 수 있는지와 수신 앱·경로가 얼마나 빨리 소비하는지의 결과입니다. 수신 창(rwnd), 혼잡 창(cwnd), 앱 큐, RTT를 각각 시간축에 놓으면 “버퍼를 키우면 빨라진다”는 단순 처방을 검증 가능한 가설로 바꿀 수 있습니다.
흐름 제어와 혼잡 제어의 병목 차이
송신자는 빠른데 수신 앱이 데이터를 읽지 않으면 수신 버퍼가 찹니다. TCP는 수신자가 광고한 창으로 더 보낼 양을 제한합니다. 이것이 흐름 제어입니다. 반대로 수신 앱은 빠르지만 경로의 공유 링크와 큐가 붐비면 송신자가 경로 상태를 추정해 전송을 조절해야 합니다. 이것이 혼잡 제어입니다.
수신 창과 혼잡 창은 각각 다른 제약이며, 애플리케이션이 제공한 데이터와 송신 버퍼·pacing 등도 실제 전송량에 영향을 줍니다. 창 하나만 크게 바꿔 모든 지연을 해결할 수는 없습니다.
수신 앱이 느려 rwnd가 줄어드는 trace와, 앱은 읽지만 손실·ECN·지연으로 cwnd가 줄어드는 trace를 분리합니다. 전자는 수신 buffer와 소비율을, 후자는 경로 queue와 혼잡 신호를 먼저 조사해야 합니다. 두 값이 동시에 작아질 수 있으므로 한 신호만 보고 원인을 단정하지 않습니다.
송신 가능량을 제한하는 두 경계
그림을 글로 읽기
- 수신 창 rwnd: 수신 버퍼·앱 소비
- 혼잡 창 cwnd: ACK·손실·ECN·지연 등
- 송신 TCP: in-flight와 가용 데이터 · 창·pacing·큐 조건
- 수신 창 rwnd → 송신 TCP: 수신자 한도
- 혼잡 창 cwnd → 송신 TCP: 경로 추정 한도
수신 창이 0이면 경로 대역폭이 남아도 새 데이터 진행이 제한됩니다. zero-window probe는 창이 다시 열렸는지 확인하는 장치이지 상대 앱의 큐를 처리하는 장치가 아닙니다. 송신 워커 수를 늘리면 상대 소비가 빨라지는 대신 송신 측 대기만 늘 수 있습니다.
송신 가능한 in-flight 데이터는 대략 min(rwnd, cwnd)와 애플리케이션·송신 큐의 공급량 중 더 작은 제약에 묶입니다. rwnd=0이면 링크가 비어도 진행이 막히고, cwnd가 작으면 수신 앱이 빨라도 경로 사용량이 제한됩니다. 이 단순식은 진단 모델이며 실제 stack의 세부 pacing과 overhead를 포함한 측정값으로 대체해야 합니다.
대역폭·RTT 곱(BDP)과 필요 진행량
경로가 초당 10MB를 전달할 수 있고 RTT가 0.1초이면 약 1MB가 확인받기 전 비행 중일 수 있어야 그 속도를 활용하기 쉽습니다. 이 관계가 대역폭-지연 곱(BDP)입니다. 사용 가능한 창이 100KB에 묶여 있다면 단순 무손실 모형의 window/RTT는 약 1MB/s가 됩니다.
| 모형 | 대역폭 | RTT | 창 | 단순 예상 제약 |
|---|---|---|---|---|
| 넉넉한 창 | 10MB/s | 0.1s | 1MB 이상 | 링크를 채울 여지 |
| 작은 창 | 10MB/s | 0.1s | 100KB | ACK 대기 때문에 약 1MB/s 수준 |
| 느린 수신 앱 | 10MB/s | 0.1s | 줄어드는 rwnd | 앱 소비가 별도 한도 |
숫자는 십진 단위의 설명 모형입니다. 혼잡 알고리즘·손실·window scaling·pacing·프로토콜 overhead에 따라 실제 속도는 다릅니다. BDP를 특정 socket buffer의 무조건적인 권장값으로 옮기지 않습니다.
10MB/s와 0.1s의 BDP가 1MB인 예에서 usable window가 100KB면 이상적인 window/RTT 상한이 약 1MB/s입니다. 이 예측은 손실 없는 단순 모델에서만 성립하므로, 실제 측정에서는 window scaling, ACK 정책, 재전송, pacing을 함께 기록해 차이를 설명합니다.
큰 버퍼와 숨겨진 지연
버퍼는 순간적인 burst를 흡수하지만 지속적으로 생산이 소비보다 빠르면 큐는 계속 찹니다. 너무 큰 큐는 데이터가 전달되기 전 오래 머무는 bufferbloat를 만들 수 있습니다. 사용자에게 필요한 최신 상태가 큐 뒤에 갇히는 실시간 서비스에서는 처리량만 올리고 응답성은 악화될 수 있습니다.
TCP의 흐름 제어가 있어도 앱이 메모리 큐에 무제한 작업을 쌓으면 앱 메모리는 보호되지 않습니다. 앱 작업 큐·소켓 전송·수신 처리의 예산을 연결해야 합니다. 이미 오래돼 의미가 없는 데이터는 프로토콜의 허용 범위 안에서 합치거나 폐기하는 별도 정책이 필요합니다.
버퍼를 키운 뒤 throughput이 올라가도 queue residence time과 p99가 늘면 실시간 요구에는 회귀일 수 있습니다. 앱 메모리 큐까지 무제한이면 TCP flow control 전에 생산자가 작업을 쌓으므로, 소켓 buffer와 별개로 앱 queue budget과 폐기·병합 정책을 둡니다.
관찰값의 시간축 비교
| 관찰 | 먼저 세울 가설 | 추가 근거 |
|---|---|---|
| rwnd 축소·수신 읽기 지연 | 수신자 처리 병목 | 수신 버퍼·CPU·앱 큐 |
| cwnd 변화·RTT·재전송 | 경로 혼잡·손실 | 경로 큐·ECN·알고리즘 |
| 앱 전송 호출 자체 지연 | 생산자 실행 지연 | 이벤트 루프·락·배치 |
| 충분한 창인데 처리량 낮음 | 앱 데이터 공급·pacing·다른 한도 | 실제 in-flight·소켓 큐 |
손실이 없다고 혼잡이 없지는 않습니다. ECN이나 지연·대역폭 추정을 사용하는 제어도 있습니다. 재전송이 늘었다고 모든 원인을 수신 앱의 느린 read로 보지도 않습니다. 실제 사용 중인 OS·알고리즘과 관찰 지점을 기록합니다.
같은 구간에서 rwnd, cwnd, RTT, retransmission, ACK 간격, 앱 read 지연, 앱 queue 길이를 함께 시계열로 기록합니다. rwnd 축소가 read 지연 직후에 오면 수신 처리 가설이 강해지고, cwnd 축소가 손실·ECN·RTT 상승과 함께 오면 경로 가설이 강해집니다. 충분한 창인데도 공급 데이터가 없으면 TCP 조정보다 producer를 먼저 봅니다.
수신 앱·경로 원인 분리와 전송 조정
한 실험은 수신 앱만 느리게 하고 경로는 유지합니다. 다른 실험은 수신 앱을 유지한 채 허가된 테스트 경로에 지연·손실을 주입합니다. 창·ACK 간격·RTT·재전송·앱 큐·요청 p99를 대조합니다.
버퍼 변경 뒤 처리량과 큐 체류 시간이 같이 개선됐는지, 단지 실패가 긴 대기로 바뀌었는지 확인합니다. 사용자 데이터의 최신성과 성공 완료율까지 유지해야 전송량 증가를 개선이라고 말할 수 있습니다.
두 실험의 예상은 각각 다릅니다. 앱만 느리게 하면 rwnd 축소와 read 지연이 나타나고, 경로에 지연·손실을 넣으면 RTT·재전송·cwnd 변화가 나타나야 합니다. 버퍼 조정 뒤에는 처리량뿐 아니라 큐 체류 시간, 오류율, 최신 데이터 지연을 함께 확인해 개선의 범위를 제한합니다.