세 가지 접근 비교
| 알고리즘 | 혼잡 신호 | 윈도우 증가 방식 | 손실 뒤 감소 |
|---|---|---|---|
| Reno 계열 | 패킷 손실 | RTT당 약 1 세그먼트(선형) | 절반(FlightSize/2) |
| CUBIC | 패킷 손실 | 시간의 3차 함수 | β=0.7배(RFC 9438 권장값) |
| BBR | 측정한 대역폭과 최소 지연 | 모델 기반(손실에 직접 반응하지 않음) | 모델에 따라 조정 |
CUBIC은 RFC 9438(2023년 발행, RFC 8312를 대체)에서 윈도우를 W_cubic(t) = C·(t−K)³ + W_max로 두고 C=0.4, β_cubic=0.7을 권장합니다. K는 손실 뒤 윈도우가 W_max로 되돌아가는 데 걸리는 시간입니다. 리눅스에서는 2.6.19 이후 CUBIC이 기본이라고 정리됩니다. 윈도우는 Compound TCP가 기본 알고리즘으로 소개되지만, 버전과 설정에 따라 다를 수 있습니다(위키백과 기준).
직접 계산해 보기: cwnd는 이렇게 움직입니다 (가상 예시)
아래는 실제 측정이 아니라 규칙을 이해하기 위한 가상 예시이며, 단위는 세그먼트, 값은 node로 검산했습니다. 세그먼트 크기는 1460바이트라고 가정해 RFC 5681의 초기 윈도우 상한 3세그먼트로 시작하고, ssthresh는 16으로 둡니다.
| RTT 번호 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| cwnd(세그먼트) | 3 | 6 | 12 | 16 | 17 | 18 | 19 |
2번째 RTT까지는 매번 두 배(슬로 스타트)이고, 12에서 다음에 24가 되면 ssthresh 16을 넘으므로 16에서 멈춘 뒤 RTT당 1씩 늘어나는 혼잡 회피로 들어간 것으로 단순화했습니다(실제로는 ACK 단위로 증가하므로 약간 다를 수 있습니다). 이제 cwnd=20일 때 중복 ACK 3개로 손실이 감지되었다고 하면, ssthresh = max(20/2, 2) = 10, 빠른 회복 진입 시 cwnd = 10 + 3 = 13이고, 회복이 끝나면 10에서 다시 선형으로 늘어납니다. 손실 한 번에 윈도우가 절반으로 줄어드는 것이 톱니 모양의 이유입니다.
CUBIC도 같은 방식으로 따라가 보겠습니다(역시 가상 예시). 손실 직전 W_max=100세그먼트였다면 손실 뒤 cwnd=100×0.7=70이고, K=∛(100×0.3/0.4)≈4.22초입니다. 그 뒤 윈도우는 t=1초에 약 86.7, 2초에 약 95.6, 3초에 약 99.3, 4초에 약 100.0으로 W_max 근처까지 빠르게 회복하고, 5초에 약 100.2, 6초에 약 102.3, 8초에 약 121.7로 W_max를 넘어서면서 다시 공격적으로 탐색합니다. 같은 상황에서 Reno 계열은 70에서 100까지 RTT당 1씩 늘리므로 30 RTT가 걸립니다. RTT가 200ms라면 약 6초로, CUBIC의 약 4.2초보다 오래 걸립니다. CUBIC의 증가가 RTT가 아닌 경과 시간에 맞춰 있다는 점이 고속·장거리 회선에서의 이점으로 설명됩니다(RTT가 매우 짧으면 Reno와 비슷하게 동작하도록 한 구간도 규격에 있습니다).
실제 사례 두 가지
사례 1. 유튜브에 적용된 BBR (2016년 이후)
BBR은 2016년 구글에서 개발된 모델 기반 알고리즘으로, 최근 송신 구간에서 관측한 최대 대역폭과 왕복 지연시간으로 네트워크 모델을 만들어 전송 속도를 정합니다. 위키백과 정리에 따르면 유튜브에 적용했을 때 BBRv1은 평균 처리량이 약 4%, 일부 국가에서는 최대 14% 높아졌다고 합니다. 또 QUIC에서도 BBR을 쓸 수 있습니다. 배울 점은 손실이 없어도 큐가 쌓이는 지연의 문제가 있고, 그에 대한 해법이 손실 기반 접근과 다른 방향으로도 가능하다는 것입니다. 다만 이 수치는 구글 환경에서의 결과이므로 모든 네트워크에 그대로 적용되지는 않습니다.
사례 2. 리눅스 기본값이 CUBIC이 된 것 (커널 2.6.19 이후)
리눅스 커널의 기본 혼잡 제어 알고리즘은 CUBIC이며, 위키백과는 리눅스 커널 2.6.19부터 기본값이라고 설명합니다. 그 때문에 웹 서버의 응답 속도 체감은 서버 쪽 알고리즘에 크게 영향을 받고, 서버 관리자는 커널 설정으로 BBR 등 다른 알고리즘을 선택해 볼 수 있습니다. 배울 점은 혼잡 제어가 송신 측 구현의 문제여서, 사용자는 바꾸기 어렵지만 서버 운영자의 선택이 체감 품질에 영향을 준다는 것입니다.
실전 점검
- 어느 알고리즘을 쓰는지 확인: 리눅스에서는
sysctl net.ipv4.tcp_congestion_control로 현재 값을 조회할 수 있습니다(변경은 서버 환경에 영향을 주므로 운영 서버에서는 계획 후 진행). - 지연이 커지면 버퍼블로트를 의심: 속도는 나오는데 게임·화상회의만 끊긴다면 큐 길이 문제일 수 있습니다.
- 속도 측정은 여러 번: 슬로 스타트 때문에 짧은 전송은 최대 속도에 도달하기 전에 끝날 수 있습니다.
- 무선 환경의 손실 해석: 와이파이·모바일에서는 혼잡이 아닌 간섭 때문에 손실이 날 수 있어, 손실 기반 알고리즘이 속도를 과하게 줄이는 경우가 있습니다.
흔한 오해와 정정
- 오해: 혼잡 제어는 상대 컴퓨터가 처리 못 할까 봐 속도를 줄이는 것이다. 실제: 수신자 보호는 흐름 제어(수신 윈도우)이고, 혼잡 제어는 중간 네트워크를 보호합니다. 실제 전송량은 둘 중 작은 값의 영향을 받습니다.
- 오해: 혼잡 제어는 TCP에만 있고 UDP는 항상 무제한이다. 실제: UDP 자체에는 없지만, QUIC 같은 UDP 위의 프로토콜은 자체 혼잡 제어를 구현합니다.
- 오해: 회선이 빠르면 전송은 곧바로 최대 속도가 된다. 실제: 슬로 스타트로 올라가는 시간이 필요하며, 지연이 클수록 그 시간이 길어집니다.
- 오해: 새 알고리즘이 모든 환경에서 우월하다. 실제: 회선 특성(지연, 손실 원인, 버퍼 크기)에 따라 결과가 달라집니다.
한계와 더 알아볼 점
혼잡 제어는 네트워크 내부를 보지 못한 채 간접 신호로 추측하기 때문에 항상 오판 가능성이 있습니다. 손실 기반은 손실의 원인이 혼잡인지 무선 간섭인지 구분하기 어렵고, 측정 기반은 측정이 부정확하면 속도가 흔들릴 수 있습니다. 서로 다른 알고리즘이 한 회선을 나눠 쓸 때의 공정성도 알고리즘 설계의 지속적인 관심사입니다. 이 글의 성능 수치는 위키백과의 정리이며, 구체적 수치가 필요하면 원 논문과 RFC를 확인하세요.
TCP 자체의 기본 원리도 궁금하다면
혼잡 제어는 TCP의 신뢰성 보장 메커니즘 중 하나입니다. TCP와 UDP의 기본적인 차이가 궁금하다면TCP와 UDP 차이 완전정복도 확인해보세요.
버퍼블로트 문제와도 연결됩니다
손실 기반 알고리즘이 버퍼가 가득 찬 뒤에야 반응하는 문제는버퍼블로트(Bufferbloat)란? 게임·화상회의만 끊기는 이유에서 다루는 현상과 밀접하게 연결되어 있습니다.
자주 묻는 질문
내가 쓰는 혼잡 제어 알고리즘을 직접 바꿀 수 있나요?
리눅스에서는 커널 설정으로 Cubic, BBR 등 사용할 알고리즘을 선택할 수 있습니다. 다만 일반 사용자가 쓰는 윈도우·맥 운영체제나 대부분의 웹 브라우저는 이런 설정을 직접 노출하지 않으며, 보통 서버 쪽 설정이 실제 체감 속도에 더 큰 영향을 줍니다.
UDP를 쓰는 스트리밍이나 게임에도 혼잡 제어가 있나요?
UDP 자체에는 혼잡 제어 기능이 없지만, UDP 위에서 동작하는 QUIC 같은 최신 프로토콜은 자체적으로 혼잡 제어 로직을 구현해 두고 있습니다. 반면 혼잡 제어가 전혀 없는 UDP 애플리케이션은 네트워크가 혼잡해도 속도를 줄이지 않아, 다른 트래픽에 부담을 줄 수 있습니다.
cwnd와 수신 윈도우(rwnd)는 어떻게 다른가요?
rwnd는 수신자가 "내 버퍼에 이만큼까지 받을 수 있다"고 알려 주는 값이고, cwnd는 송신자가 네트워크 상태를 추측해 스스로 정하는 값입니다. 송신자는 둘 중 작은 쪽을 넘겨서 보내지 않습니다.
중복 ACK가 왜 손실 신호가 되나요?
수신자는 순서가 맞지 않는 세그먼트를 받으면 마지막으로 순서대로 받은 지점의 ACK를 다시 보냅니다. 같은 ACK가 3번 중복되면 중간 하나가 사라졌을 가능성이 높다고 보고, RFC 5681은 타이머를 기다리지 않고 재전송하도록 정합니다.
ping 시간이 길면 혼잡 제어 때문인가요?
꼭 그렇지 않습니다. 물리적 거리, 무선 구간, 라우터 큐 등 여러 원인이 있습니다. 다만 손실 기반 알고리즘이 라우터 버퍼를 가득 채우면 큐잉 지연이 커질 수 있어 버퍼블로트와 연결해서 살펴볼 만합니다.
이어서 읽어 보세요
- TCP와 UDP 차이: 신뢰성과 속도의 설계 차이
- 버퍼블로트 가이드: 큐가 길어질 때 지연이 커지는 이유
- MTU 크기 가이드: 세그먼트 크기가 정해지는 배경
- 핑과 지연시간 가이드: RTT를 읽는 방법