합동회사 코무라소프트
4장

흐름 제어 — TCP 의 슬라이딩 윈도우

수신 측은 ACK 마다 「앞으로 몇 바이트 받을 수 있는가」를 광고하고, 송신 측은 ACK 대기 바이트 수를 그 범위 안에 담는다. 이 창의 미끄러짐이 스루풋의 상한을 정한다.

빠른 송신 측은 느린 수신 측을 익사시킨다

재전송 구조가 갖춰져도 아직 약속은 완성되지 않습니다. 송신 측 서버가 고성능이고, 수신 측이 비력한 모바일 단말이라면? 도착한 데이터는 일단 수신 측의 수신 버퍼에 놓여, 앱이 recv() 로 읽어내기를 기다립니다. 앱의 읽기가 송신 페이스를 따라잡지 못하면 버퍼는 넘치고, 모처럼 도착한 데이터를 버리고 재전송을 받는 처지가 됩니다. 이래서는 본말전도입니다.

그래서 TCP 는 약속 그 3 의 전반, 흐름 제어를 넣습니다. 구조는 제 3 장의 ACK 에의 합승입니다. 수신 측은 ACK 를 돌려줄 때마다 「확인한 위치에서 앞으로 이만큼이라면 받을 수 있다」는 빈 용량 — 윈도우(rwnd) — 를 함께 신고합니다. 송신 측은 송신 완료이면서 아직 ACK 가 돌아오지 않은 바이트 수(in-flight)가 이 범위를 넘지 않는 한도 내에서만 보내 나아갑니다.

바이트열이 송신 완료·확인 완료, 송신 완료·미확인, 윈도우 내에서 송신 가능, 윈도우 밖에서 송신 불가의 4 구간으로 나뉘고, ACK 와 함께 창이 오른쪽으로 미끄러지는 모습의 그림

확인 완료의 끝(ack = 20001)에서 윈도우 5000 바이트 분량이 「보내도 좋은 범위」. ACK 가 나아가면 창째로 오른쪽으로 미끄러지므로, 슬라이딩(미끄러지는) 윈도우라고 부릅니다.

바이트열을 4 가지 색으로 칠해 나눈다

송신 측에서 보면, 바이트의 나열은 언제나 4 개의 구간으로 칠해 나눌 수 있습니다. ack = 20001, 윈도우 5000, 바이트 23000 까지 송신 완료, 라는 예로 살펴봅시다.

〜20000: 송신 완료·확인 완료
이제 볼일 끝. 버퍼에서 버려도 좋다
20001〜23000: 송신 완료·미확인(in-flight = 3000 바이트)
비행 중. 잃어버리면 재전송하므로, 아직 수중에도 보관하고 있다
23001〜25000: 미송신·송신 가능(남은 범위 2000 바이트)
창의 오른쪽 끝은 20000 + 5000 = 25000. 여기까지는 ACK 를 기다리지 않고 보내도 좋다
25001〜: 미송신·송신 불가
창의 밖. ACK 가 나아가 창이 미끄러지기를 기다린다

윈도우가 0 으로 광고되는 일도 있습니다(제로 윈도우). 수신 앱이 버퍼를 읽어내지 않고 있는 상태로, 송신 측은 송신을 멈추고 윈도우 프로브라는 작은 문의로 가끔 상황을 물으면서 기다립니다. 캡처에 제로 윈도우가 줄지어 있다면, 의심할 것은 네트워크가 아니라 수신 측 앱의 처리 정체입니다.

소문제 4-1 — 윈도우의 끝을 손으로 계산한다

「어디까지 보내도 좋은가」의 경계선을 바이트의 번호로 정확히 그을 수 있게 합니다.

Q1. 수신 측이 ACK 에 실어 광고하는 윈도우(rwnd)의 값이 나타내는 것은 어느 것입니까.

Q2. 송신 측은 ack = 20001(20000 까지 확인 완료), 광고 윈도우 5000 바이트의 ACK 를 받았습니다. 이미 바이트 23000 까지 송신 완료했습니다. 지금 추가로 보내도 좋은 것은 몇 바이트입니까.

바이트

Q3. 수신 측이 윈도우 0 을 광고해 왔습니다(제로 윈도우). 송신 측의 올바른 행동은 어느 것입니까.

창의 크기가 속도의 상한을 정한다 — 윈도우 ÷ RTT

흐름 제어에는 중요한 부작용이 있습니다. 송신 측은 ACK 대기의 양을 윈도우 이하로 유지하므로, 1 RTT 동안 보낼 수 있는 것은 최대라도 윈도우 1 잔 분량입니다. 즉, 아무리 대역폭이 굵어도

스루풋 상한 = 윈도우 ÷ RTT

를 넘을 수 없습니다. 윈도우 100 KB·RTT 100 밀리초라면, 100,000 바이트 ÷ 0.1 초 = 1 MB/초가 천장입니다. 회선을 빈틈없이 다 쓰려면 대역폭 × RTT(대역폭 지연 곱, BDP) 이상의 윈도우가 필요해집니다. 「가까운 서버에서는 빠른데, 해외 서버에서만 느리다」의 대부분은 이 식으로 설명할 수 있습니다.

시뮬레이터의 동작 개요(텍스트판): RTT·윈도우·대역폭의 3 개 슬라이더를 움직이면, 1 RTT 에 보낼 수 있는 양(= 윈도우), 윈도우 ÷ RTT 로 정해지는 스루풋 상한, 대역폭 × RTT(BDP), 실효 스루풋(윈도우 제약과 대역폭 제약 중 작은 쪽)이 수치로 갱신됩니다. 아울러, 경로라는 파이프에 in-flight 세그먼트가 어느 정도 차 있는가(충전율과 비행 중 세그먼트 수의 기준)가 가로 막대로 표시되고, 지금의 상한을 정하고 있는 것이 윈도우인지 대역폭인지가 문장으로 표시됩니다.

시뮬레이터로 시험해 봤으면 하는 3 가지 실험

  1. RTT 만 10 배로 한다 — 윈도우와 대역폭은 그대로. 상한이 10 분의 1 로 떨어지고, 파이프가 텅텅 비는 것을 확인해 주세요.
  2. 윈도우를 BDP 에 맞춘다 — 충전율이 딱 100% 가 되어, 제약이 「윈도우」에서 「대역폭」으로 바뀌는 경계를 찾아 주세요. 소문제 4-2 의 제 3 문의 답과 같은 값이 될 것입니다.
  3. 윈도우를 BDP 보다 크게 한다 — 상한은 더 이상 늘지 않습니다. 창을 넓혀도 파이프보다 굵게는 흐르지 않는 것을 확인해 주세요.

소문제 4-2 — 윈도우와 RTT 가 스루풋을 정한다

시뮬레이터의 계산식을 자신의 손으로도 확인합니다. 1 MB = 100 만 바이트로 합니다.

Q4. 윈도우 100 KB(100,000 바이트), RTT 100 밀리초의 커넥션에서 낼 수 있는 스루풋의 상한은 몇 MB/초입니까. (1 MB = 100 만 바이트)

MB/초

Q5. 대역폭 1 Gbps 의 고속 회선인데도, 원거리(RTT 가 큰)의 전송만 느리다, 는 일이 일어납니다. 이유로 올바른 것은 어느 것입니까.

Q6. 대역폭 10 MB/초·RTT 100 밀리초의 경로를 빈틈없이 다 쓰려면, 최소 몇 MB 의 윈도우가 필요합니까. (대역폭 × RTT 를 계산한다. 1 MB = 100 만 바이트)

MB

이 장에서 가져갈 것

  • 흐름 제어는 수신 측의 사정에 맞추는 구조. rwnd 는 수신 버퍼의 빈 공간의 신고
  • 보내도 좋은 오른쪽 끝 = 확인 완료의 끝 + 윈도우. in-flight 가 윈도우를 넘지 않도록 보낸다
  • 스루풋 상한 = 윈도우 ÷ RTT. 다 쓰려면 윈도우 ≥ 대역폭 × RTT(BDP)
  • 제로 윈도우의 주범은 수신 측 앱의 읽기 정체. 네트워크를 의심하기 전에 앱을 본다

다만, 상대의 사정에 맞추는 것만으로는 아직 부족합니다. 다음 장은 약속 그 3 의 후반 — 도중의 네트워크의 사정에 맞추는 혼잡 제어입니다. 또 하나의 창 cwnd 가 등장합니다.