メインコンテンツへスキップ

よくある誤解として、TCPがデータの確実な配信を保証しているというものがある。実際、TCPが保証するのは、データを受信ホストのTCPスタックに届けるか、送信アプリケーションにエラーを報告することである。残念ながら、このエラー報告では実際に配信されたデータ量が示されない。また、受信側のTCPスタックと受信アプリケーションの間には大きな違いがある。

基本的な障害シナリオは2つ存在する。最初のシナリオでは、送信側TCPスタックが送信中のデータに対するTCP確認応答を受信していない。この場合、送信アプリケーションはsend呼び出しを継続してTCPスタックの送信バッファにデータを追加できる。TCPスタックが送信をタイムアウトすると、送信アプリケーションが次に呼び出すsend(またはreceive)はETIMEDOUTエラーを示す。 アプリケーションは問題が発生したことを認識しますが、正常に送信されたデータ量が不明です。成功とは、送信側TCPスタックが受信側TCPスタックからデータに対する確認応答を受信したことを意味します。

2つ目のシナリオでは、送信側のTCPスタックがデータを送信した際、確認応答ではなくリセットを受信します。このリセットは、受信側のTCPスタックがソケットを閉じているか、ファイアウォールなどのネットワークデバイスがタイムアウトしたことを示している可能性があります。送信アプリケーションが次にsend(またはreceive)を呼び出すと、ECONNRESETエラーが発生します。 このシナリオでは、送信アプリケーションが「最後のsend呼び出しのデータのみが失敗した」と推測できると思うかもしれませんが、それは誤りです。送信側のTCPスタックが複数のsend呼び出しのデータを1つのTCPセグメントにバッファリングし、そのセグメントがリセットを引き起こした可能性や、一連のTCPセグメントが送信された後、最初の発信元セグメントが引き金となってリセットが発生し、それが送信元に到達した可能性もあるからです。 送信アプリケーションが推測できるのは、全データが正常に送信されなかったということだけです。

3つ目の障害シナリオは、TCP(送信または受信)スタックやネットワークとは無関係です。受信アプリケーションにデータを読み取れないバグがあると仮定します。受信側のTCPスタックは、TCP受信バッファが満杯になるまでデータを受信し続け、TCP確認応答を送信します。 ただし、これは最大64Kバイトのデータ(TCPウィンドウスケーリングがサポートされている場合はそれ以上)に達する可能性があります。受信アプリケーションを再起動する必要がある場合、TCP受信バッファ内の全データは失われます。受信アプリケーションが終了した際、受信TCPスタックは送信TCPスタックにリセットを送信すべきですが(必ずしも送信しない場合があります)。次に、既に閉じられた接続向けのセグメントを受信した際にリセットを送信します。 送信アプリケーションの観点では、これは第二のシナリオと類似している。ただし、受信側のTCPスタックがデータを受信確認しても、エラーが発生した場合、送信側が受信アプリケーションがデータを読み取ったと仮定することは安全ではないことを示している。

これらの障害シナリオから得られる教訓は、アプリケーション層の応答がない場合、送信タイムアウトやリセットエラーは、送信されたデータの一部、あるいは全てが受信側アプリケーションによって読み取られていない可能性があることを示している。このため、全てのアプリケーションにおいてアプリケーション層の応答を含めること、接続の再確立と未応答データの再送信の準備を整えること、そして失われたのは応答である可能性があるため重複データに対処できることを推奨する。

© 2024 ストラタス・テクノロジーズ