QUICをゆっくり解説(13):ロス検知
2021年10月26日 火曜日
CONTENTS
QUICは、信頼性を提供するトランスポート層です。そのため、パケットが配送中に欠落した場合、その欠落を判定し、パケット内の情報を再送する必要があります。QUICは、前回の記事で紹介した確認応答を利用して、パケットの欠落を判定します。
送信者にとって、あるパケットに対する確認応答が返ってこない場合、欠落したのか、遅延しているのかはっきりとは判断できません。
- 遅延しているのに欠落したと判断した場合は、誤った再送(spurious retransmission)を引き起こしてしまいます
- 欠落したのに遅延していると判断した場合は、必要な再送が実行されません
パケットのロス検知は一般的に難しい問題です。TCPでは、さらに確認応答の曖昧性もあるので、判定アルゴリズムが複雑になる傾向にありました。QUICでは、TCPの経験から学んで確認応答の曖昧性をなくし、比較的簡潔なロス検知のアルゴリズムを定義しています。
今回は、QUICのロス検知について説明します。前回書きましたが、ロス検知はパケット番号空間ごとに実行されます。
PTO(Probe Timeout)
QUICのロス検知は、確認応答を受け取ることを前提としています。そのため、確認応答が返ってこないことには、ロス検知がうまく動きません。
通信のある時点において、「直近でない過去」に送ったパケット群には、それ以降送信したパケット群により、確認応答が返ってくる確率が高いです。一方、直近に送ったパケット群には、以下の理由で確認応答が返ってくる確率が低くなります。
- 直近に送信したパケット群が欠落した
- 直近に送信したパケット群は届いたが、送り返した確認応答が欠落した
このような状況をテールロス(tail loss)と言います。テールロスを速やかに解決する方法として、プローブのパケットの送信があります。一定時間のあと、相手が確認応答を返すようなパケットを送るのです。この一定時間のことを PTO(Probe Timeout)と呼びます。QUICでも、PTO方式を採用しています。
QUICでは、ACKフレーム、PADDINGフレーム、そしてCONNECTION_CLOSEフレーム以外のフレームを含んだパケットを受信した場合、確認応答を返さなければならないと定義されています。送信者は、このようなパケットを送信するたびに、PTOを再設定します。タイムアウトの値は、計測したRTTから決定されますが、詳細は割愛します。
PTOがタイムアウトした場合、確認応答を引き起こすパケットを送ります。プローブパケットの候補は以下のとおりです。
- 送信予定の新規のパケット
- 再送予定のパケット
- PINGフレームを格納したパケット
確認応答によるロス検知
確認応答を受け取って、パケット番号の範囲にギャップを見つけたとしましょう。たとえば、前回の例に出てきた [10〜11,13]
だと、12が欠落したパケットの候補となります。新規のギャップを見つけてすぐに欠落だと判断すると、誤った再送を引き起こします。直後に [10〜13]
という確認応答を受け取るかもしれませんからね。
そこで、以下のどちらかの条件が満たされてはじめて、欠落したと判断します。
- 確認応答されたパケットよりも、kPacketThreshold個以前に送られている (kPacketThresholdの推奨値は3)
- 送信した時間から一定時間経過した (一定時間は計測したRTTから決定しますが、詳細は割愛します)
(2)を実現するために、ギャップを見つけるとロスタイマーが動き出します。実装としては、この際PTOタイマーを止められるので、ロスタイマーとPTOタイマーが同時に動くことはありません。また、パケット空間ごとにタイマーを用意するのではなく、1つのタイマーでロス検知を実現できます。詳細を知りたい方は、RFC9002に掲載されている疑似コードをお読みください。