メインコンテンツまでスキップ

6. 損失検出 (Loss Detection)

QUIC送信者は確認応答 (acknowledgments) を使用して失われたパケットを検出し、PTOを使用して確認応答を受信することを保証します。セクション6.2を参照してください。このセクションでは、これらのアルゴリズムの説明を提供します。

パケットが失われた場合、QUICトランスポートは、データを再送信する、更新されたフレームを送信する、またはフレームを破棄するなどして、その損失から回復する必要があります。詳細については、[QUIC-TRANSPORT]のセクション13.3を参照してください。

損失検出 (loss detection) はパケット番号空間ごと (per packet number space) に分離されています。これはRTT測定と輻輳制御とは異なります。RTTと輻輳制御はパスの属性であるのに対し、損失検出は鍵の可用性にも依存するためです。


6.1. 確認応答ベースの検出 (Acknowledgment-Based Detection)

確認応答ベースの損失検出は、TCPの高速再送 (Fast Retransmit) [RFC5681]、早期再送 (Early Retransmit) [RFC5827]、前方確認応答 (Forward Acknowledgment) [FACK]、SACK損失回復 [RFC6675]、およびRACK-TLP [RFC8985] の精神を実装しています。このセクションでは、これらのアルゴリズムがQUICでどのように実装されているかの概要を示します。

パケットは、以下のすべての条件を満たす場合に失われたと宣言されます:

  • パケットは未確認であり、送信中 (in flight) であり、確認されたパケットの前に送信された。

  • パケットは確認されたパケットのkPacketThreshold個前に送信された(セクション6.1.1)、または十分に長い時間前に送信された(セクション6.1.2)。

確認応答は、後で送信されたパケットが配信されたことを示し、パケットと時間の閾値はパケットの並べ替えに対するある程度の許容範囲を提供します。

パケットを誤って失われたと宣言すると、不必要な再送信が発生し、損失を検出した際の輻輳制御器の動作により性能が低下する可能性があります。実装は、偽の再送信を検出し、将来の偽の再送信と損失イベントを減らすためにパケットまたは時間の並べ替え閾値を増やすことができます。適応的な時間閾値を持つ実装は、回復遅延を最小限に抑えるために、より小さい初期並べ替え閾値から始めることを選択できます (MAY)。

6.1.1. パケット閾値 (Packet Threshold)

パケット並べ替え閾値 (kPacketThreshold) の推奨 (RECOMMENDED) 初期値は3であり、これはTCP損失検出のベストプラクティス [RFC5681] [RFC6675] に基づいています。TCPと同様の動作を維持するために、実装は3未満のパケット閾値を使用すべきではありません (SHOULD NOT)。[RFC5681]を参照してください。

一部のネットワークでは、より高度なパケットの並べ替えが発生し、送信者が偽の損失を検出する可能性があります。さらに、TCPパケットを観察して並べ替えることができるネットワーク要素がQUICではそれができず、QUICパケット番号が暗号化されているため、QUICではTCPよりもパケットの並べ替えがより一般的である可能性があります。RACK [RFC8985] のように、偽の損失検出後に並べ替え閾値を増やすアルゴリズムは、TCPで有用であることが証明されており、QUICでも少なくとも同程度に有用であることが期待されます。

6.1.2. 時間閾値 (Time Threshold)

同じパケット番号空間内の後のパケットが確認されると、エンドポイントは、閾値時間量の前に送信された場合、より早いパケットを失われたと宣言すべきです (SHOULD)。パケットを早すぎる時期に失われたと宣言することを避けるために、この時間閾値は、kGranularity定数で示されるローカルタイマーの粒度以上に設定しなければなりません (MUST)。時間閾値は次のとおりです:

max(kTimeThreshold * max(smoothed_rtt, latest_rtt), kGranularity)

最大確認パケットの前に送信されたパケットがまだ失われたと宣言できない場合、残りの時間に対してタイマーを設定すべきです (SHOULD)。

max(smoothed_rtt, latest_rtt)を使用することで、以下の2つのケースから保護されます:

  • 最新のRTTサンプルが平滑化されたRTTよりも低い場合。これはおそらく、確認応答がより短いパスに遭遇した並べ替えによるものです。

  • 最新のRTTサンプルが平滑化されたRTTよりも高い場合。これはおそらく、実際のRTTが持続的に増加しているが、平滑化されたRTTがまだ追いついていないためです。

推奨 (RECOMMENDED) される時間閾値 (kTimeThreshold) は、RTT乗数として表され、9/8です。推奨 (RECOMMENDED) されるタイマー粒度値 (kGranularity) は1ミリ秒です。

注意: TCPのRACK [RFC8985] は、同様の目的のために5/4に相当するわずかに大きい閾値を指定しています。QUICでの経験は、9/8がうまく機能することを示しています。

実装は、絶対閾値、以前の接続からの閾値、適応閾値、またはRTT変動を含む閾値を試すことができます (MAY)。小さい閾値は並べ替えの弾力性を低下させ、偽の再送信を増やし、大きい閾値は損失検出の遅延を増やします。


6.2. プローブタイムアウト (Probe Timeout)

プローブタイムアウト (PTO) は、確認応答要請パケット (ack-eliciting packets) が予想される期間内に確認されない場合、またはサーバーがクライアントのアドレスをまだ検証していない可能性がある場合に、1つまたは2つのプローブデータグラムの送信をトリガーします。PTOにより、接続は末尾パケットまたは確認応答の損失から回復できます。

損失検出と同様に、PTOはパケット番号空間ごと (per packet number space) です。つまり、PTO値は各パケット番号空間に対して計算されます。

PTOタイマーの期限切れイベントはパケット損失を示すものではなく、以前に未確認のパケットを失われたとマークしてはなりません (MUST NOT)。新しく確認要請されたパケットの確認応答を受信したとき、損失検出はパケットと時間閾値メカニズムによって指示されたとおりに進行します。セクション6.1を参照してください。

QUICで使用されるPTOアルゴリズムは、TCPの末尾損失プローブ (Tail Loss Probe) [RFC8985]、RTO [RFC5681]、およびF-RTOアルゴリズム [RFC5682] の信頼性機能を実装しています。タイムアウト計算は、TCPのRTO期間 [RFC6298] に基づいています。

6.2.1. PTOの計算 (Computing PTO)

確認応答要請パケットが送信されると、送信者は次のようにPTO期間のタイマーをスケジュールします:

PTO = smoothed_rtt + max(4*rttvar, kGranularity) + max_ack_delay

PTO期間は、送信者が送信されたパケットの確認応答を待つべき時間量です。この期間には、推定ネットワークRTT (smoothed_rtt)、推定の変動 (4*rttvar)、および受信者が確認応答の送信を遅延させる可能性のある最大時間を考慮したmax_ack_delayが含まれます。

InitialまたはHandshakeパケット番号空間に対してPTOがアームされる場合、PTO期間計算のmax_ack_delayは0に設定されます。これは、ピアがこれらのパケットを意図的に遅延させないことが期待されるためです。[QUIC-TRANSPORT]のセクション13.2.1を参照してください。

PTO期間は、タイマーが直ちに期限切れにならないように、少なくともkGranularityでなければなりません (MUST)。

複数のパケット番号空間で確認応答要請パケットが送信中の場合、タイマーはInitialおよびHandshakeパケット番号空間のより早い値に設定しなければなりません (MUST)。

エンドポイントは、ハンドシェイクが確認されるまで、アプリケーションデータパケット番号空間に対してPTOタイマーを設定してはなりません (MUST NOT)。そうすることで、ピアがまだパケットを処理する鍵を持っていない場合、またはエンドポイントがまだ確認応答を処理する鍵を持っていない場合に、パケット内の情報を再送信することを防ぎます。例えば、これはクライアントが0-RTTパケットをサーバーに送信する場合に発生する可能性があります。クライアントは、サーバーがそれらを復号化できるかどうかを知らずにこれを行います。同様に、これはサーバーが、クライアントがサーバーの証明書を検証したことを確認する前、つまりこれらの1-RTTパケットを読み取ることができる前に、1-RTTパケットを送信する場合に発生する可能性があります。

送信者は、確認応答要請パケットが送信または確認されるたび、またはInitialまたはHandshake鍵が破棄されるたび([QUIC-TLS]のセクション4.9)に、PTOタイマーを再起動すべきです (SHOULD)。これにより、PTOが常にRTTの最新の推定値に基づいて設定され、パケット番号空間を越えて正しいパケットに対して設定されることが保証されます。

PTOタイマーが期限切れになると、PTOバックオフを増やさなければならず (MUST)、その結果、PTO期間が現在の値の2倍に設定されます。確認応答を受信すると、PTOバックオフ係数はリセットされますが、以下の場合を除きます。ハンドシェイク中、サーバーがパケットに応答するのに通常より長い時間がかかる場合があります。そのようなサーバーを繰り返されるクライアントプローブから保護するために、サーバーがクライアントのアドレスの検証を完了したことをまだ確信していないクライアントでは、PTOバックオフはリセットされません。つまり、クライアントは、Initialパケットで確認応答を受信してもPTOバックオフ係数をリセットしません。

送信者のレートのこの指数的な削減は重要です。なぜなら、連続するPTOは、深刻な輻輳によるパケットまたは確認応答の損失によって引き起こされる可能性があるためです。複数のパケット番号空間で確認応答要請パケットが送信中である場合でも、PTOの指数的増加はすべての空間で発生し、ネットワーク上の過剰な負荷を防ぎます。例えば、Initialパケット番号空間でのタイムアウトは、Handshakeパケット番号空間でのタイムアウトの長さを2倍にします。

連続するPTO期限切れが発生する期間の合計長は、アイドルタイムアウト (idle timeout) によって制限されます。

時間閾値損失検出のためにタイマーが設定されている場合、PTOタイマーを設定してはなりません (MUST NOT)。セクション6.1.2を参照してください。時間閾値損失検出のために設定されたタイマーは、ほとんどの場合PTOタイマーよりも早く期限切れになり、偽にデータを再送信する可能性が低くなります。

6.2.2. ハンドシェイクと新しいパス (Handshakes and New Paths)

同じネットワーク上で再開された接続は、以前の接続の最終的な平滑化されたRTT値を、再開された接続の初期RTTとして使用できます (MAY)。以前のRTTが利用できない場合、初期RTTは333ミリ秒に設定すべきです (SHOULD)。これにより、TCPの初期RTOで推奨されているように、ハンドシェイクが1秒のPTOで開始されます。[RFC6298]のセクション2を参照してください。

接続は、PATH_CHALLENGEを送信してからPATH_RESPONSEを受信するまでの遅延を使用して、新しいパスの初期RTTを設定できます (MAY)(付録A.2のkInitialRttを参照)が、その遅延はRTTサンプルとみなすべきではありません (SHOULD NOT)。

InitialおよびHandshake鍵が破棄されると(セクション6.4を参照)、それらの鍵で送信されたすべてのInitialパケットとHandshakeパケットは、その確認応答を処理できないため、もはや確認できません。したがって、それらは送信中バイト (bytes in flight) から削除されます。PTOおよび損失検出タイマーをリセットしなければなりません (MUST)。鍵を破棄することは前進を示し、損失検出タイマーは現在破棄されているパケット番号空間に対して設定されていた可能性があるためです。

6.2.2.1. アドレス検証の前 (Before Address Validation)

サーバーがパス上のクライアントのアドレスを検証するまで、送信できるデータの量は、[QUIC-TRANSPORT]のセクション8.1で指定されているように、受信したデータ量の3倍に制限されます。追加のデータを送信できない場合、サーバーのPTOタイマーは、クライアントからデータグラムを受信するまでアームされてはなりません (MUST NOT)。PTOで送信されたパケットは反増幅制限にカウントされるためです。

サーバーがクライアントからデータグラムを受信すると、増幅制限が増加し、サーバーはPTOタイマーをリセットします。PTOタイマーが過去の時刻に設定された場合、それは直ちに実行されます。これにより、ハンドシェイクの完了に重要なパケットの前に新しい1-RTTパケットを送信することを避けます。特に、これは0-RTTが受け入れられたがサーバーがクライアントのアドレスの検証に失敗した場合に発生する可能性があります。

サーバーはクライアントから受信するデータグラムが増えるまでブロックされる可能性があるため、サーバーがアドレス検証を完了したことを確信するまで、サーバーのブロックを解除するためにパケットを送信することはクライアントの責任です([QUIC-TRANSPORT]のセクション8を参照)。つまり、クライアントがHandshakeパケットの確認応答を受信しておらず、ハンドシェイクが確認されていない場合([QUIC-TLS]のセクション4.1.2を参照)、送信中のパケットがなくてもPTOタイマーを設定しなければなりません (MUST)。PTOが発火すると、クライアントはHandshake鍵を持っている場合はHandshakeパケットを送信しなければならず (MUST)、そうでない場合は少なくとも1200バイトのペイロードを持つUDPデータグラム内でInitialパケットを送信しなければなりません (MUST)。

6.2.3. ハンドシェイク完了の高速化 (Speeding up Handshake Completion)

サーバーが重複するCRYPTOデータを含むInitialパケットを受信した場合、クライアントがInitialパケットで送信されたサーバーのすべてのCRYPTOデータを受信しなかったか、クライアントの推定RTTが小さすぎると仮定できます。クライアントがHandshake鍵を取得する前にHandshakeまたは1-RTTパケットを受信した場合、サーバーの一部またはすべてのInitialパケットが失われたと仮定できます。

これらの条件下でハンドシェイクの完了を高速化するために、エンドポイントは、接続ごとに限られた回数、PTO期限切れ前に未確認のCRYPTOデータを含むパケットを送信できます (MAY)。ただし、[QUIC-TRANSPORT]のセクション8.1のアドレス検証制限に従います。接続ごとに最大1回これを行うことは、単一のパケット損失から迅速に回復するのに十分です。処理できないパケットを受信したことに応答して常にパケットを再送信するエンドポイントは、無限のパケット交換を作成するリスクがあります。

エンドポイントは、統合パケット([QUIC-TRANSPORT]のセクション12.2を参照)を使用して、各データグラムが少なくとも1つの確認応答を引き出すことを保証することもできます。例えば、クライアントはPINGおよびPADDINGフレームを含むInitialパケットを0-RTTデータパケットと統合でき、サーバーはPINGフレームを含むInitialパケットを最初のフライトの1つ以上のパケットと統合できます。

6.2.4. プローブパケットの送信 (Sending Probe Packets)

PTOタイマーが期限切れになると、送信者はパケット番号空間でプローブとして少なくとも1つの確認応答要請パケットを送信しなければなりません (MUST)。エンドポイントは、単一の失われたデータグラムによる高コストな連続PTO期限切れを避けるため、または複数のパケット番号空間からデータを送信するために、確認応答要請パケットを含む最大2つのフルサイズのデータグラムを送信できます (MAY)。PTOで送信されるすべてのプローブパケットは、確認応答要請でなければなりません (MUST)。

タイマーが期限切れになったパケット番号空間でデータを送信することに加えて、送信者は、可能であればパケットを統合して、送信中のデータを持つ他のパケット番号空間から確認応答要請パケットを送信すべきです (SHOULD)。これは、サーバーがInitialとHandshakeの両方のデータを送信中に持っている場合、またはクライアントがHandshakeとアプリケーションデータの両方を送信中に持っている場合に特に価値があります。ピアは2つのパケット番号空間のうち1つに対してのみ受信鍵を持っている可能性があるためです。

送信者がPTOでより高速な確認応答を引き出したい場合、パケット番号をスキップして確認応答遅延を排除できます。

エンドポイントは、PTO期限切れで送信されるパケットに新しいデータを含めるべきです (SHOULD)。新しいデータを送信できない場合、以前に送信されたデータを送信できます (MAY)。実装は、アプリケーションの優先順位に基づいて新しいまたは再送信されたデータを送信することを含め、プローブパケットの内容を決定するための代替戦略を使用できます (MAY)。

送信者は、送信する新しいまたは以前に送信されたデータを持っていない場合があります。例として、次のイベントシーケンスを考えてください:新しいアプリケーションデータがSTREAMフレームで送信され、失われたとみなされ、新しいパケットで再送信され、その後元の送信が確認されます。送信するデータがない場合、送信者は単一のパケットでPINGまたは他の確認応答要請フレームを送信し、PTOタイマーを再アームすべきです (SHOULD)。

あるいは、確認応答要請パケットを送信する代わりに、送信者はまだ送信中の任意のパケットを失われたとマークできます (MAY)。そうすることで追加のパケットの送信を避けますが、偽にパケットを失われたと宣言するリスクが増加し、その結果、輻輳制御器による不必要なレート削減が発生します。

連続するPTO期間は指数的に増加し、その結果、パケットがネットワークで引き続きドロップされると、接続回復遅延が指数的に増加します。PTO期限切れ時に2つのパケットを送信すると、パケットドロップに対する弾力性が向上し、連続するPTOイベントの確率が低下します。

PTOタイマーが複数回期限切れになり、新しいデータを送信できない場合、実装は毎回同じペイロードを送信するか、異なるペイロードを送信するかを選択する必要があります。毎回同じペイロードを送信する方が簡単で、最優先のフレームが最初に到着することを保証します。毎回異なるペイロードを送信すると、偽の再送信の可能性が減少します。


6.3. リトライパケットの処理 (Handling Retry Packets)

Retryパケットにより、クライアントは別のInitialパケットを送信し、事実上接続プロセスを再開します。RetryパケットはInitialパケットが受信されたが処理されなかったことを示します。Retryパケットは、パケットが処理されたことを示さず、パケット番号を指定しないため、確認応答として扱うことはできません。

Retryパケットを受信したクライアントは、保留中のタイマーをリセットすることを含め、輻輳制御と損失回復状態をリセットします。特に暗号化ハンドシェイクメッセージを含む他の接続状態は保持されます。[QUIC-TRANSPORT]のセクション17.2.5を参照してください。

クライアントは、最初のInitialパケットを送信してからRetryまたはバージョンネゴシエーションパケットを受信するまでの期間を、サーバーへのRTT推定値として計算できます (MAY)。クライアントは、初期RTT推定値のデフォルトの代わりにこの値を使用できます (MAY)。


6.4. 鍵とパケット状態の破棄 (Discarding Keys and Packet State)

InitialおよびHandshakeパケット保護鍵が破棄されると([QUIC-TLS]のセクション4.9を参照)、それらの鍵で送信されたすべてのパケットは、その確認応答を処理できないため、もはや確認できません。送信者は、それらのパケットに関連するすべての回復状態を破棄しなければならず (MUST)、それらを送信中バイト (bytes in flight) のカウントから削除しなければなりません (MUST)。

エンドポイントは、Handshakeパケットの交換を開始するとInitialパケットの送受信を停止します。[QUIC-TRANSPORT]のセクション17.2.2.1を参照してください。この時点で、すべての送信中Initialパケットの回復状態が破棄されます。

0-RTTが拒否されると、すべての送信中0-RTTパケットの回復状態が破棄されます。

サーバーが0-RTTを受け入れるが、Initialパケットの前に到着する0-RTTパケットをバッファリングしない場合、初期の0-RTTパケットは失われたと宣言されますが、これは頻繁ではないことが予想されます。

鍵は、それらで暗号化されたパケットが確認または失われたと宣言されてからしばらくして破棄されることが予想されます。ただし、InitialおよびHandshake秘密は、HandshakeおよびThe 1-RTT鍵がクライアントとサーバーの両方で利用可能であることが証明されるとすぐに破棄されます。[QUIC-TLS]のセクション4.9.1を参照してください。