要約

  • Silly Window Syndromeは単発の小さなセグメントではなく、わずかなウィンドウ前進が次の小さな送信を繰り返し生む安定した循環である。
  • TCPは受信側で小幅な更新を留保し、送信側でも非効率な送信を待たせる。待機が行き詰まりにならないよう、例外タイマーも備える。

受信アプリケーションが、ほぼ満杯のバッファーから50バイトだけ読み出したとする。50バイト分の空きは実在する。受信TCPがそれを直ちに通知すれば、送信側は50バイトを正当に送れる。その50バイトが届き、アプリケーションがまた消費すれば、同じ量の空きが戻る。ACKは次の50バイト分の機会を伝える。個々の判断に誤りはないのに、接続全体は50バイト刻みのリズムから抜け出せなくなる。

David ClarkはRFC 813で、1982年にこの現象をSilly Window Syndrome(SWS)と名づけた。焦点は「小さなパケットが一つある」ことではない。一度できた小さな分割が、長い転送の途中で安定したパターンとして維持されることにある。データの自然な境界が利用可能ウィンドウを一度だけ分割し、その後はACKとウィンドウ更新が同じ大きさの断片を次々に作る。送信がいったん止まらない限り、断片をまとめ直す自然な契機がない。

この循環を説明するため、RFC 813は受信側の「提示ウィンドウ」と送信側の「利用可能ウィンドウ」を分けた。受信側が1,000バイトを提示しても、未確認の950バイトがすでにネットワーク上にあれば、新たに使えるのは50バイトしかない。その50バイトを送り、ACKによって右端が50バイトだけ進めば、次に使える量も50バイトになる。ウィンドウ欄の数値が大きくても、右端の前進幅が小さければ送信単位は小さいままである。

RFC 813が報告した影響は、ヘッダー比率の悪化だけではなかった。不適切なウィンドウ処理は、スループットとCPU利用効率を数割ではなく数倍の規模で悪化させ得るとされた。平均セグメント長が両端の扱える大きさの10分の1になり、再送も大きく増えた歴史的事例が記されている。これは1980年代初頭の観察であり、現在の実装普及率を示す資料ではない。それでも、SWSが単なる美観ではなく、資源消費を増幅するフィードバック問題だったことは明瞭である。

受信側の解決策は、空き容量と今すぐ公表する受信クレジットを同一視しないことだった。アプリケーションが少量を消費しても、受信TCPは通知する右端を固定したままにできる。空きは内部に蓄え、十分な量になった時点でまとめてウィンドウを開く。長く待ちすぎれば転送パイプラインが空になり、遅延が増える。一方、細かく開きすぎればネットワークとCPUを消費しながらスループットも落ちる。RFC 813は、少なくとも相応の大きさのセグメントを許せるまで待つ方向に寄せるべきだとした。

RFC 1122はこの知見をホスト要件へ移した。4.2.3.3節は、受信TCPにSWS回避アルゴリズムを必須とする。提案された規則では、まだ通知していない空きが「受信バッファーの一定割合」と「実効送信MSS」の小さい方に達するまで、RCV.NXT + RCV.WNDを固定する。推奨割合は2分の1である。現実的なバッファー構成なら、ウィンドウは細かなバイト単位ではなく、おおむね一つのセグメントを支えられる幅で進む。

慎重でない受信側から自分を守るには、送信側にも規則が必要となる。RFC 1122の4.2.3.4節は、送信TCPにもSWS回避を必須とした。最大長のセグメントを送れる場合、所定の条件でPUSH対象の待機データをすべて送れる場合、これまで観測した最大ウィンドウの少なくとも2分の1を使える場合、または例外タイマーが満了した場合に送る、という条件を示す。小さな利用可能ウィンドウは送信の許可ではあるが、直ちに使い切る命令ではない。

送信側には不確実性もある。受信側は自分のバッファー総量を知っているが、送信側は知らない。接続中に観測した最大送信ウィンドウを推定値にできるものの、受信側は後からバッファーを縮小し得る。古い最大値の一定割合を永遠に待てば、効率化の規則そのものが停止を招く。そこで例外タイマーが待機を打ち切る。RFC 9293は0.1秒から1.0秒という推奨範囲を残すが、ここから各OSの実際の既定値までは断定できない。

現行TCP仕様を統合したRFC 9293も、送信側と受信側の双方にSWS回避を要求する。同時にNagleアルゴリズムとの違いを明記した。Nagleはアプリケーションがデータを小刻みに渡すために生じる小さなセグメントを抑える。送信側SWS回避は、受信ウィンドウの右端が小刻みに進むために生じる小さなセグメントを抑える。両者は補完関係にあるが、原因は同じではない。