[PonsWarp 개념 교실 18] AIMD — 혼잡 제어의 고전
쉽게 말하면, AIMD는 "잘 흐르면 조금씩 키우고, 막히면 크게 줄이는" 혼잡 제어 규칙이다.

PonsWarp는 RTT와 DataChannel의 bufferedAmount를 관찰해 cwnd(congestion window)를 조절한다. 다만 현재 구현은 진단용에 가깝고, 실제 hot path의 주 페이싱은 SCTP와 bufferedAmount 제어가 담당한다.
왜 필요한가
송신자가 네트워크 상태를 모른 채 속도를 고정하면 두 문제가 생긴다.
- 너무 느리면 회선이 빈다.
- 너무 빠르면 버퍼가 쌓이고 지연과 재전송이 늘어난다.
AIMD는 네트워크 상태를 직접 완벽히 예측하지 않고, 결과를 보고 창을 조절한다.
혼잡 없음 → cwnd를 조금 증가
혼잡 감지 → cwnd를 곱셈으로 감소
Additive Increase
RTT가 안정적이고 bufferedAmount가 창의 80%보다 낮으면 cwnd를 더한다.
typescriptconst increase = rtt < 10 ? 256 * 1024 : rtt < 150 ? 64 * 1024 : 16 * 1024; cwnd = Math.min(MAX_CWND, cwnd + increase);
낮은 RTT에서는 256KiB씩 공격적으로, 높은 RTT에서는 16KiB씩 천천히 증가한다.
Multiplicative Decrease
RTT가 최소 RTT의 2배를 넘거나 bufferedAmount가 cwnd를 초과하면 혼잡으로 판단한다.
typescriptcwnd = Math.max(MIN_CWND, cwnd * 0.7);
현재 창의 70%로 줄인다. 한 번에 일정량을 빼는 것이 아니라 비율로 줄이므로 큰 창일수록 크게 줄고 작은 창일수록 작게 줄어든다.
PonsWarp 적용 지점
| 항목 | 값 | 증거 |
|---|---|---|
| 초기 cwnd | 4MiB | networkAdaptiveController.ts:41 |
| 최소 cwnd | 512KiB | networkAdaptiveController.ts:55 |
| 혼잡 조건 | RTT ratio > 2.0 또는 buffer > cwnd | networkAdaptiveController.ts:117-118 |
| 감소 | cwnd × 0.7 | networkAdaptiveController.ts:120-123 |
| 증가 | RTT별 256/64/16KiB | networkAdaptiveController.ts:133-140 |
| 배치 크기 | cwnd의 20% ÷ chunkSize | networkAdaptiveController.ts:143-151 |
| RTT 입력 | WebRTC candidate-pair stats | networkAdaptiveController.ts:82-94 |
지금 돌아보는 판단
AIMD는 네트워크를 완벽하게 모델링하지 않고도 안정적인 피드백 제어를 제공한다. 하지만 PonsWarp에서는 주 전송 경로가 이미 bufferedAmount, SCTP 수위, 경로별 profile을 사용한다. 그래서 AIMD는 실제 전송을 단독 지배하기보다 진단·튜닝 보조 역할에 머문다.
RTT ratio가 혼잡 신호가 되는 이유
AIMD가 보는 것은 “현재 속도가 빠른가”가 아니라 같은 경로에서 지연이 늘었는가다. PonsWarp의 측정값은 기준 RTT와 최근 RTT의 비율로 해석된다. baseline이 40ms이고 최근 RTT가 60ms라면 ratio는 1.5다. 처리량이 아직 나오고 있어도 큐가 생겨 패킷이 돌아오는 시간이 늘었다는 뜻이다.
textsample RTT ──► ratio = sample / baseline │ 낮음 ────────┼────── 높음 cwnd += α │ cwnd *= β 조금 확장 │ 빠르게 축소
Additive Increase는 성공할 때 창을 조금씩 늘린다. Multiplicative Decrease는 혼잡 신호가 보이면 곱셈으로 줄인다. 이 비대칭이 필요한 이유는 혼잡이 시작된 뒤에도 같은 양을 계속 더하면 큐를 더 악화시키기 때문이다. 줄일 때는 큰 폭으로 비우고, 다시 올릴 때는 측정값을 확인하며 천천히 회복한다.
그냥 고정 속도로 보내면 안 되나?
고정 속도는 네트워크가 항상 같은 환경이라는 가정이 필요하다. Wi-Fi에서 사용자가 이동하거나 모바일 화면이 잠기면 RTT와 bufferedAmount가 즉시 변한다. 가장 느린 환경에 맞추면 데스크톱 회선이 낭비되고, 평균 환경에 맞추면 나쁜 순간에 큐가 쌓인다.
다만 AIMD를 만능 혼잡 제어로 오해하면 안 된다. 현재 PonsWarp에서는 실제 hot path의 주 페이싱을 SCTP와 DataChannel bufferedAmount 제어가 맡고, AIMD는 진단·튜닝 관점의 신호에 가깝다. 측정용 cwnd를 도입했다고 해서 그것이 자동으로 send loop의 단일 진실이 되지는 않는다.
| 요소 | 질문 | 책임 |
|---|---|---|
| baseline RTT | 평상시 왕복 시간은 얼마인가 | 비교 기준 |
| sample RTT | 지금 왕복 시간은 얼마인가 | 현재 상태 |
| ratio | 지연이 얼마나 늘었나 | 혼잡 신호 |
cwnd | 동시에 허용할 양은 얼마인가 | 페이싱 후보 |
| bufferedAmount | 브라우저 큐가 얼마나 찼나 | 즉시 안전장치 |
경계값과 구현 판단
baseline을 한 번의 우연한 샘플로 정하면 안 된다. 연결 직후 ICE·암호화 협상 지연을 baseline으로 잡을 수 있기 때문이다. 안정된 샘플을 모으고, 0에 가까운 값으로 나누지 않도록 하며, ratio가 튀어도 단 한 번의 샘플로 창을 무너뜨리지 않는 완충이 필요하다. 반대로 혼잡 신호를 계속 무시하면 AIMD를 둔 의미가 없다.
재구축 시에는 측정과 제어를 분리한다. 먼저 RTT·bufferedAmount·ACK 지연을 기록하고, 그 로그로 증가·감소 규칙을 검증한 뒤 hot path에 연결한다. 이 순서가 없으면 네트워크 문제와 writer 병목을 AIMD가 잘못 줄인 것처럼 보이게 만든다.
한 문장 정리
AIMD는 네트워크가 안정적이면 cwnd를 조금씩 늘리고 RTT·버퍼 혼잡이 감지되면 70%로 줄이는 피드백 제어이며, PonsWarp에서는 WebRTC 통계 기반 튜닝 보조로 구현되어 있다.
관련 개념: [개념 14 — DataChannel] · [개념 16 — in-flight 윈도우]
RTT ratio가 혼잡 신호가 되는 이유
절대 RTT 하나만 보면 네트워크가 원래 느린지, 지금 혼잡한지 구분할 수 없다. PonsWarp는 estimatedRtt / minRtt 비율을 사용한다.
textmin RTT = 20ms, current RTT = 30ms → ratio 1.5 min RTT = 20ms, current RTT = 50ms → ratio 2.5 → 혼잡 의심
최소 RTT는 같은 경로에서 관찰한 이상적인 지연에 가깝고, 현재 RTT가 그보다 크게 늘면 큐가 쌓였다고 추정한다.
왜 증가량이 RTT별로 다른가
LAN의 256KiB 증가와 TURN의 16KiB 증가는 같은 AIMD지만 공격성이 다르다. relay에서 큰 증가량을 쓰면 작은 혼잡에도 window가 급격히 커지고 다시 줄어드는 진동이 생긴다.
PonsWarp는 update 사이 최소 100ms를 둬 통계 노이즈에 과민 반응하지 않게 한다. cwnd의 20%를 batch size로 바꾸는 단계도 있어, 혼잡 창이 작아지면 워커 요청량도 함께 줄어든다.
실제 hot path와의 경계
AIMD 구현이 있다고 해서 모든 전송이 AIMD만으로 움직이는 것은 아니다. 실제 전송은 DataChannel bufferedAmount, profile별 low water, prepare-ahead credit, partition policy를 함께 사용한다. AIMD는 WebRTC stats와 버퍼 상태를 해석해 튜닝값을 제안하는 보조 계층이다.
이 구분을 하지 않으면 “AIMD가 12MiB를 정했다”처럼 코드가 실제로 하지 않는 일을 설명하게 된다.
다시 만든다면
혼잡 제어 이벤트에 rttRatio, cwndBefore, cwndAfter, bufferedAmount, pathKind를 함께 기록하겠다. 그래야 0.7 감소가 실제 안정성을 높였는지, 단순히 throughput을 낮춘 것인지 비교할 수 있다.