TCPのRTO、往復時間と再送までの待ち時間が違う理由

幅が順に広くなる三つの薄紫のアーチを薄緑の帯が通り、最も広いアーチの前に桃色の球が置かれている。

通信の往復に100ミリ秒かかるなら、100ミリ秒待って返事がなければ送り直す。それだけでは、少し遅れて届く応答まで取りこぼしてしまいます。TCPの再送タイムアウト、RTO(Retransmission Timeout)は、測った往復時間そのものではなく、応答を待つために決める時間です。

ここではRFC 6298の計算方法を、小さな数値例で追います。平均に相当する値、時間の揺れ、待ち時間の下限を分けると、「RTTが変わったのにRTOが同じ」という結果も読み解けます。

簡単にまとめると?

  • RTTは往復時間の観測値、RTOは再送タイマーの待ち時間。平滑化したRTTに、時間の揺れを考慮した余裕を加えます。
  • 揺れを更新するときには、更新前の平滑化RTTを使います。計算順序を入れ替えると、同じ観測値でも結果が変わります。
  • RFC 6298が推奨する1秒の下限を採ると、下限適用前の計算値が変化しても、最終RTOは1秒のままになることがあります。
  • タイマー満了による再送では待ち時間を倍にします。RTTの更新、下限の適用、タイムアウト後の倍増は、それぞれ別の処理です。

観測する時間と、待つための時間

TCPはデータの受信を確認応答(ACK)で確かめます。データを送ってから対応するACKを受け取るまでの時間が、ここで扱うRTTのサンプルです。経路や処理の条件が変われば、その値も揺れます。まだACKが来ていないという事実だけで、データが失われたと断定できるわけではありません。

現行TCP基本仕様のRFC 9293は、RTOを動的に決め、RFC 6298の手順で計算することを要求しています。RFC 6298は2011年のProposed Standard、RFC 9293は2022年のInternet Standardです。以下は仕様に沿った計算例であり、特定OSの現在の設定値や実際の回線を測った結果ではありません。[1][2]

「いつもの時間」と「そこからのずれ」を持つ

計算にはSRTT(平滑化したRTT)とRTTVAR(RTTの変動を表す値)を使います。SRTTは新しい観測で少しずつ動く基準、RTTVARは観測がその基準からどれくらい離れたかを蓄える値です。RTTVARは二乗した偏差の平均ではなく、時間と同じ単位を持ちます。

初回のサンプルをRとすると、SRTT=R、RTTVAR=R÷2で始めます。その後のサンプルR′では、まずRTTVARを「旧RTTVARの3/4+|旧SRTT−R′|の1/4」、次にSRTTを「旧SRTTの7/8+R′の1/8」へ更新します。これはRFC 6298が推奨する係数を使う場合です。下限適用前のRTOは「SRTT+max(G, 4×RTTVAR)」となります。Gは時計の粒度、maxは二つのうち大きい方です。[1]

式が長く見えても、役割は二つです。SRTTで観測の中心を追い、RTTVARでその周囲の揺れに備えます。新しいRTTが大きく外れたとき、SRTTだけを見ていると小さな変化に見えても、待つための余裕は大きくなりえます。

100、120、400ミリ秒を順に観測すると

計算条件を固定しましょう。Gは1ミリ秒、上記の係数を使い、採用可能なRTTサンプルとして100、120、400ミリ秒が順番に得られたとします。この間に再送によるサンプルの曖昧さはなく、タイマー満了による倍増もない例です。

初回100ミリ秒では、SRTTは100、RTTVARは50。したがって下限適用前RTOは100+4×50=300ミリ秒です。次の120ミリ秒では旧SRTTとの差は20。RTTVARは50×3/4+20×1/4=42.5、SRTTは100×7/8+120×1/8=102.5となり、下限適用前RTOは272.5ミリ秒です。

2回目のRTTは長くなったのに、計算値は300から272.5ミリ秒へ短くなりました。理由は、SRTTが2.5増えた一方で、4×RTTVARが200から170へ減ったためです。「今回のRTTが大きいほど、RTOも必ず大きくなる」という一対一の対応ではありません。

RTTサンプル100、120、400ミリ秒から求めたSRTTは100、102.5、139.6875ミリ秒、RTTVARは50、42.5、106.25ミリ秒。下限適用前RTOは300、272.5、564.6875ミリ秒で、1秒の下限適用後はいずれも1000ミリ秒。
同じ更新式を3回のサンプルに適用した独自計算。すべてミリ秒。下段ではRFC 6298の推奨に従い、計算値が1秒未満なら1秒を採用しています。実測データではありません。

3回目の400ミリ秒では、旧SRTTとの差が297.5へ広がります。RTTVARは42.5×3/4+297.5×1/4=106.25、SRTTは139.6875となり、下限適用前RTOは564.6875ミリ秒です。SRTTの増加は37.1875ミリ秒ですが、余裕の部分は170から425ミリ秒へ増えています。今回のずれを待ち時間に反映しているのは、主に後者です。

下限があると、変化は表面に出ない

RFC 6298は、計算したRTOが1秒未満なら1秒に引き上げることを推奨しています。規定の強さはSHOULDであり、すべての実装が常に同じ下限を使っているという観測ではありません。この推奨を採用した上の例では、3回とも最終RTOは1000ミリ秒になります。[1]

ここで最終RTOだけを記録すると、内部計算が変わったことは見えません。しかし、SRTTもRTTVARも更新されています。診断するときには、測定RTT、更新後SRTT、更新後RTTVAR、下限適用前の値、最終RTOを分けて並べると、どの処理が結果を決めたかを確認できます。

もう一つ、この例のGを変えてみましょう。3回目は4×RTTVAR=425ミリ秒なので、Gを1から10ミリ秒にしてもmaxの結果は425のままです。時計の粒度を変更すれば、この式の結果がいつでも変わるわけではありません。どちらの項が大きいかを先に見る必要があります。

更新順序を入れ替えると、別の計算になる

3回目のRTTVARを求める前にSRTTを139.6875へ更新してしまうと、400との差を260.3125として扱うことになります。その誤った順序ではRTTVARは96.953125、下限適用前RTOは527.5ミリ秒です。正しい564.6875ミリ秒より37.1875ミリ秒短くなります。

しかも、この例では誤った計算でも1秒の下限に引き上げられます。最終RTOが正しく見えることだけでは、内部の更新式も正しいとは確認できません。実装や計算表を点検するなら、下限をかける前の中間値まで比べることが有効です。これは上の数値から得た比較であり、特定の実装で不具合を観測したという話ではありません。

タイムアウト後の倍増と、RTTの測定を混ぜない

RFC 6298のタイマー管理では、満了時に未確認の最も早いセグメントを再送し、RTOを倍にして次のタイマーを始めます。また、再送したセグメントは、どの送信へのACKか曖昧になるため、原則としてRTT測定に使いません。これはKarnのアルゴリズムです。タイムスタンプオプションで曖昧さを除ける場合は例外があります。[1]

別の単純な例として、RTOが1秒の時点から、ACKも新しい測定もなく満了が続く場合を考えます。最初の満了まで1秒、次は2秒、その次は4秒待つため、基準の送信時刻を0とすれば満了時刻は1、3、7秒です。「1、2、4」は待つ間隔であって、最初からの経過時刻ではありません。この例は上限や接続の打切りを考えない短い3区間だけの計算です。

実際のTCPにはRTO以外の損失回復もあります。RFC 9293は、再送キューのタイムアウト処理と、別途規定されたFast Retransmitなどの機構を区別しています。RTOからすべての再送時刻を逆算したり、HTTPリクエストをもう一度実行してよいかを判断したりはできません。TCPのタイマー、接続の終了判断、アプリケーションの再試行を、それぞれの層の情報で確認することが大切です。[2]

出典

  1. RFC 6298 — Computing TCP’s Retransmission Timer(2011年6月、Proposed Standard)。第2〜5節。計算順序、係数、下限、サンプル選択、タイマー管理。
  2. RFC 9293 — Transmission Control Protocol (TCP)(2022年8月、Internet Standard / STD 7)。第3.8.1節、第3.10.8節。TCP基本仕様と再送タイムアウト。