QUICをゆっくり解説(13):ロス検知

2021年10月26日 火曜日


【この記事を書いた人】
山本 和彦

Haskellコミュニティでは、ネットワーク関連を担当。 4児の父であり、家庭では子供たちと、ジョギング、サッカー、スキー、釣り、クワガタ採集をして過ごす。

「QUICをゆっくり解説(13):ロス検知」のイメージ

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] という確認応答を受け取るかもしれませんからね。

そこで、以下のどちらかの条件が満たされてはじめて、欠落したと判断します。

  1. 確認応答されたパケットよりも、kPacketThreshold個以前に送られている (kPacketThresholdの推奨値は3)
  2. 送信した時間から一定時間経過した (一定時間は計測したRTTから決定しますが、詳細は割愛します)

(2)を実現するために、ギャップを見つけるとロスタイマーが動き出します。実装としては、この際PTOタイマーを止められるので、ロスタイマーとPTOタイマーが同時に動くことはありません。また、パケット空間ごとにタイマーを用意するのではなく、1つのタイマーでロス検知を実現できます。詳細を知りたい方は、RFC9002に掲載されている疑似コードをお読みください。

山本 和彦

2021年10月26日 火曜日

Haskellコミュニティでは、ネットワーク関連を担当。 4児の父であり、家庭では子供たちと、ジョギング、サッカー、スキー、釣り、クワガタ採集をして過ごす。

Related
関連記事