はじめに
TCP互換プロトコルを作っていると、「再送タイマにセットする値はどうやって計算するのかな?」と思うことがよくあります。
詳しくは、RFC6298を読めばよいのですが、ぱっと実装するときのポイントを以下にまとめておきます。
初期RTO
1秒(SHOULD)
過去のRFC(2988など)では3秒でした。なので、1秒以上の初期RTOでもOKです(MAY)。
RTO計算
1回目のRTT計測時
RTT計測値をRとすると、
SRTT <- R
RTTVAR <- R/2
RTO <- SRTT + 4*RTTVAR
2回目以降のRTT計測時
RTT計測値をR'とすると、
RTTVAR <- 0.75 * RTTVAR + 0.25 * |SRTT - R'|
SRTT <- 0.875 * SRTT + 0.125 * R‘
RTO <- SRTT + 4*RTTVAR
このあたりはMUST要求。
最大値
60秒(MAY)
Linuxでは120秒ですね。
最小値
1秒(SHOULD)
BSDでは200ms。Linuxでは100msです。
どこかの記事で読みましたがSolarisは10msだったかどうとか・・・。
ちなみに、AIXはごく最近まで1秒を律儀に守っていたようです。
nsの初期値でも200msが使われていますが、とりあえず200ms位がいいかもしれません。
RTT計測方法
詳細な定義はありませんが、Karnのアルゴリズムの利用はMUSTです。
(再送されたパケットに対するRTT計測はしない、という決まりごと)
1RTTに1回は計測したほうがいいらしいです。
昔は、タイムスタンプオプションをよく見かけましたが、最近はタイムスタンプオプションを使わない実装も増えてきましたね。
細かい挙動
SYNの再送
3秒(MUST)
RFC6298から追加された条項。というよりも、初期RTOが3秒から1秒に変更されたことによる但し書き。
Backoffの初期化
再送後の初回RTT計測後(再送ではなく、新しいデータを送信して、それに対するACKが到着したとき)、Backoffを戻す
SRTTとRTTVARの初期化
BackOffを行うときに、SRTTとRTTVARはクリアしてもよい(MAY)
RFCに書いていないこと
いろいろありますが、以下の処理などがあります
ackoff値が8を超過しているとき
RTTVAR = RTTVAR + SRTT, SRTT = 0
3回以上再送タイムアウトが発生するときは、途中の経路が変更された可能性があると睨んで、RTT推定値(特にSmoothedRTT)をクリアします。
おわりに
性能向上のポイントは、プロトコルよりも実装の高速化です。単純な計算処理でできるようにしましょう。とはいえ、プロトコル上のムダは、プロトコルで解決するべきです。
ちなみに、実装とRFCは別です。通信の相手先がRFC準拠と思い込まないほうがよいでしょう。
このあたり、流行りのQUICはどうなっているのか、気になりますね。