파일을 다운로드할 때 처음엔 빠르게 받아지다가 갑자기 느려지는 경험을 해본 적 있으신가요? TCP는 빠른 전송만을 목표로 하지 않습니다. 수신 측이 처리할 수 있는 속도, 그리고 네트워크 자체가 감당할 수 있는 용량까지 실시간으로 고려하며 전송 속도를 조절합니다.
이 속도 조절을 담당하는 두 메커니즘이 있습니다. 그렇다면 이 두 메커니즘은 서로 어떻게 다르고, 각각 어떤 상황에서 속도를 줄이는 걸까요?
이 글에서는 수신 측 버퍼를 보호하는 흐름 제어(슬라이딩 윈도우), 네트워크 혼잡을 감지해 전송량을 조절하는 혼잡 제어(Slow Start, AIMD), 그리고 실제 TCP가 느려지는 상황을 흐름 중심으로 정리해 보겠습니다.
요약
- 흐름 제어: 수신 측 처리 속도에 맞춰 송신 속도를 조절 — 슬라이딩 윈도우 방식
- 혼잡 제어: 네트워크 혼잡을 감지해 전송량을 줄임 — Slow Start, AIMD
- 핵심 차이: 흐름 제어는 수신 측 보호, 혼잡 제어는 네트워크 보호
- 실제 전송량: min(rwnd, cwnd) — 두 윈도우 중 작은 값으로 결정
- 결론: TCP가 느려지는 이유는 대부분 이 두 가지 메커니즘이 동작하기 때문
1. 왜 속도 조절이 필요한가
TCP는 단순히 데이터를 빠르게 전송하는 것만이 목표가 아닙니다. 수신 측이 처리할 수 있는 속도, 그리고 라우터 큐가 처리할 수 있는 최대 대역폭을 모두 고려해야 합니다.
속도 조절이 없다면 두 가지 문제가 발생합니다.
- 수신 측 버퍼 오버플로우: 송신 속도가 수신 측 처리 속도보다 빠르면 수신 버퍼가 가득 차서 패킷이 버려집니다.
- 네트워크 혼잡: 너무 많은 데이터가 동시에 네트워크에 쏟아지면 라우터 큐가 가득 차서 패킷이 손실됩니다.
이 두 문제를 해결하는 메커니즘이 각각 흐름 제어와 혼잡 제어입니다.
2. 흐름 제어 (Flow Control)
흐름 제어는 수신 측이 처리할 수 있는 만큼만 데이터를 보내도록 송신 속도를 조절하는 메커니즘입니다. 수신 측을 보호하는 것이 목적입니다.
슬라이딩 윈도우 (Sliding Window)
TCP는 매 패킷마다 ACK를 기다리지 않고, 한 번에 여러 패킷을 전송할 수 있습니다. 이때 한 번에 보낼 수 있는 데이터의 최대량을 윈도우 크기(Window Size) 라고 합니다.
수신 측은 TCP 헤더의 수신 윈도우(rwnd, Receive Window) 필드를 통해 현재 자신의 버퍼 여유 공간을 송신 측에 알립니다.

수신 측 버퍼: 4096바이트 중 1024바이트 사용 중
→ rwnd = 3072 (여유 공간)
→ 송신 측은 한 번에 최대 3072바이트까지 전송 가능
수신 측이 데이터를 처리해 버퍼가 비워지면
→ rwnd가 증가 → 송신 측이 더 많이 전송 가능
수신 측이 처리를 못 따라오면
→ rwnd가 감소 → 송신 측이 전송량을 줄임
윈도우 크기가 0이 되면?
수신 측 버퍼가 가득 차면 rwnd = 0을 보냅니다. 송신 측은 전송을 중단하고 Zero Window Probe 패킷을 주기적으로 보내 수신 측 버퍼가 비워졌는지 확인합니다.
3. 혼잡 제어 (Congestion Control)
혼잡 제어는 네트워크 전체의 혼잡 상태를 감지해 전송량을 조절하는 메커니즘입니다. 네트워크를 보호하는 것이 목적입니다.
수신 측이 처리를 잘 하고 있어도 중간 네트워크 경로가 혼잡하면 패킷이 손실될 수 있습니다. 혼잡 제어는 이 상황을 감지하고 전송량을 줄여 라우터 큐의 혼잡이 해소될 시간을 확보합니다.
TCP는 혼잡 윈도우(cwnd, Congestion Window) 를 별도로 관리합니다. 실제 전송 가능한 데이터 양은 흐름 제어의 rwnd와 혼잡 제어의 cwnd 중 작은 값으로 결정됩니다.
실제 전송 가능량 = min(rwnd, cwnd)
혼잡 제어의 4가지 단계

① Slow Start (슬로우 스타트)
연결 초기에 cwnd를 1 MSS(Maximum Segment Size)에서 시작해 ACK를 받을 때마다 2배씩 증가시킵니다. "Slow"라는 이름과 달리 지수적으로 빠르게 증가합니다. ssthresh(슬로우 스타트 임계값)에 도달하면 선형 증가로 전환합니다.
초기: cwnd = 1 MSS
1 RTT 후: cwnd = 2 MSS
2 RTT 후: cwnd = 4 MSS
3 RTT 후: cwnd = 8 MSS
...
ssthresh에 도달하면 Congestion Avoidance로 전환
② Congestion Avoidance (혼잡 회피)
cwnd가 ssthresh에 도달하면 지수 증가에서 선형 증가로 전환합니다. 1 RTT마다 cwnd를 1 MSS씩 증가시켜 혼잡 발생을 방지하며 천천히 전송량을 늘립니다.
ssthresh = 16 MSS 에 도달 후:
매 RTT마다 cwnd += 1 MSS
③ Fast Retransmit (빠른 재전송)
중복 ACK(Duplicate ACK)를 3번 연속 수신하면 타임아웃을 기다리지 않고 즉시 해당 패킷을 재전송합니다. 중복 ACK는 패킷이 손실됐지만 이후 패킷은 정상 수신됐다는 신호입니다. 8편에서 다룬 Fast Retransmit과 동일한 메커니즘입니다.
ACK 100 수신
ACK 100 수신 (중복 1)
ACK 100 수신 (중복 2)
ACK 100 수신 (중복 3)
→ 즉시 재전송 (타임아웃 대기 없음)
④ Fast Recovery (빠른 복구)
Fast Retransmit 후 Slow Start로 돌아가지 않고 혼잡 회피 단계로 진입합니다. cwnd를 절반으로 줄이고, ssthresh를 현재 cwnd의 절반으로 설정합니다.
패킷 손실 감지 (타임아웃):
ssthresh = cwnd / 2
cwnd = 1 MSS
→ Slow Start부터 재시작
패킷 손실 감지 (3중복 ACK):
ssthresh = cwnd / 2
cwnd = ssthresh
→ Congestion Avoidance로 진입 (Fast Recovery)
4. 흐름 제어 vs 혼잡 제어 비교
| 항목 | 흐름 제어 | 혼잡 제어 |
|---|---|---|
| 목적 | 수신 측 버퍼 보호 | 네트워크 혼잡 방지 |
| 제어 주체 | 수신 측이 송신 측에 알림 | 송신 측이 자체 판단 |
| 윈도우 | rwnd (수신 윈도우) | cwnd (혼잡 윈도우) |
| 혼잡 감지 방법 | rwnd = 0 알림 | 패킷 손실 (타임아웃, 중복 ACK) |
| 주요 알고리즘 | 슬라이딩 윈도우 | Slow Start, AIMD, Fast Recovery |
AIMD (Additive Increase Multiplicative Decrease)
혼잡 제어의 핵심 원리입니다. 혼잡이 없으면 전송량을 선형적으로 증가시키고(Additive Increase), 혼잡이 감지되면 전송량을 절반으로 줄입니다(Multiplicative Decrease). 이 방식으로 여러 TCP 연결이 네트워크 대역폭을 균등하게 분배할 수 있습니다.
5. 실제로 TCP가 느려지는 상황
초기 연결 시 느린 이유
Slow Start로 인해 연결 초기에는 작은 cwnd에서 시작합니다. 짧은 파일을 여러 번 요청하는 경우(예: 웹페이지의 많은 작은 리소스)에 매번 Slow Start가 반복되어 전체 성능이 저하됩니다. HTTP/2가 멀티플렉싱을 도입한 이유 중 하나입니다.
패킷 손실 후 느려지는 이유
타임아웃으로 인한 패킷 손실 감지 시 cwnd가 1 MSS로 떨어지고 Slow Start부터 다시 시작합니다. 네트워크가 불안정할수록 이 현상이 반복됩니다.
장거리 통신이 느린 이유
RTT가 크면 ACK를 받는 데 시간이 오래 걸려 cwnd가 천천히 커집니다. 예를 들어 RTT가 100ms면 Slow Start에서 cwnd가 두 배가 되는 데 100ms가 걸립니다.
추가 팁
BBR (Bottleneck Bandwidth and RTT)
구글이 개발한 혼잡 제어 알고리즘입니다. 기존 AIMD 방식(패킷 손실 기반)과 달리 RTT와 대역폭을 직접 측정해 혼잡을 판단합니다. 고속/고지연 네트워크에서 기존 방식보다 훨씬 높은 처리량을 보입니다. Linux 커널 4.9부터 기본 포함됩니다.
TCP vs QUIC에서의 혼잡 제어
HTTP/3의 기반인 QUIC는 UDP 위에서 동작하지만 자체적인 혼잡 제어를 구현합니다(RFC 9002). QUIC는 스트림별로 독립적인 혼잡 제어를 적용해 하나의 스트림에서 패킷 손실이 발생해도 다른 스트림에 영향을 주지 않습니다.
📌 정리
- 흐름 제어는 슬라이딩 윈도우(rwnd)로 수신 측 버퍼를 보호합니다.
- 혼잡 제어는 cwnd를 조절해 네트워크 혼잡을 방지합니다.
- Slow Start → Congestion Avoidance → Fast Retransmit → Fast Recovery 순으로 동작합니다.
- 실제 전송량은 min(rwnd, cwnd)로 결정됩니다.
- TCP가 느려지는 이유는 대부분 이 두 메커니즘이 전송량을 줄이고 있기 때문입니다.
📌 실무에서 중요한 이유
- 대용량 파일 전송 시 TCP 윈도우 크기가 성능의 병목이 될 수 있습니다. 서버의
tcp_rmem,tcp_wmem커널 파라미터 튜닝이 필요합니다. - 패킷 손실률이 높은 환경(모바일 네트워크 등)에서 TCP 성능이 급격히 저하되는 이유가 혼잡 제어 때문입니다. 이런 환경에서는 QUIC/UDP 기반 전송이 유리합니다.
- 클라우드 환경에서 인스턴스 간 네트워크 성능 측정 시 TCP 윈도우 크기와 RTT가 함께 고려되어야 합니다.
참고 자료
'cs 기초 > 네트워크' 카테고리의 다른 글
| [네트워크] 패킷이 손실되면 TCP는 어떻게 복구할까? (재전송, RTO) (0) | 2026.05.15 |
|---|---|
| [네트워크] TCP 연결은 어떻게 시작되고 종료될까? (Handshake) (0) | 2026.05.14 |
| [네트워크] IP 주소와 MAC 주소: 왜 두 가지 주소가 필요한가? (0) | 2026.04.27 |
| [네트워크] TCP와 UDP: 어떻게 다르고, 언제 선택해야 하는가? (0) | 2024.06.12 |
| [네트워크] ARP 프로토콜: 어떻게 동작하고, 왜 위험한가? (0) | 2024.06.12 |