通信リトライ
何が問題か?
接続失敗、または、通信中の意図しない無応答、切断で、接続をやり直したいことがある。
無闇に接続し直そうとすると、それ自体が輻輳、過負荷を引き起こす。
TCP/IP スタック自体がリトライをやっている。
接続時の SYN パケット
通信時の RTO
IP, UDP にはリトライの概念がない。送ったらそれで終わり。
TCP では、接続維持のためのパケットはなくても構わないことになっている。
接続維持のためのパケットとして
OS の TCP/IP スタックはそれぞれ異なっていて、それぞれで別のチューニングが必要になっている。
OS レベルの設定は、他の通信も絡んでくるため、個別のアプリケーションに合わせて変更すべきではない。
アプリケーションでのリトライはどうすべきなのか?
アプリケーションの要件により、対処方法が変わってくる。
人に問い合わせることができるかどうか
通信の重要度がどこまで高いのか
例えば、後回しにできるなら、次の機会まで待つ
既に切断されているのか、それともまだ通信可能なのかをどうやって判定するか?
少なくとも言えること
OS レベルの設定は、他の通信も絡んでくるため、個別のアプリケーションに合わせて変更すべきではない。
待ち時間なしでのリトライは絶対に行ってはならない。
可能であれば、リトライの間隔は徐々に延ばしていくのが望ましい。
パケットがまったく送受信されていない状態で接続状況を知る方法は根本的に存在しない。
基本的には以下の2つの方法が取られる。
alive パケットを定期的に送信する。(送信先がまだいるかどうかがわからない点に注意)
ポーリングでパケットを送信して、その応答を確認する。
通信障害の状態として、基本的には、以下が考えられる。
名前解決に失敗した。
送ったパケットに対して経路無しのICMPパケットが来た。
突然RSTが送られてきた。
送信したが、相手からのACK応答がない。
受信待ちだが受信するはずのパケットがいつまでも来ない。
関連
RFC 2988 Computing TCP's Retransmission Timer RFC 6298 Computing TCP's Retransmission Timer RFC 6592 The Null Packet (ジョークRFCであることに注意) RFC 1122 Requirements for Internet Hosts -- Communication Layers section-4.2.3.6 TCP Keep-Alives
TCP Keep-Alive はデフォルトでは無効でなくてはならない。
TCP Keep-Alive パケットの送信間隔は、デフォルトでは2時間未満にしてはならない。
RFC 793 TRANSMISSION CONTROL PROTOCOL - DARPA INTERNET PROGRAM PROTOCOL SPECIFICATION 調整できるパラメータ
TCP SYN リトライ回数
通信中、応答タイムアウト時間
リトライ間隔
Windows
MaxSynRetransmissions
SYN の再送信回数
TcpMaxDataRetransmissions
TCP のデータ再送信回数
Linux
/proc/sys/net/ipv4/tcp_syn_retries
以下のコマンドで、現在のTCP/IPスタックのグローバル設定値を見ることができる。
netsh interface tcp show global
サーバー側のアプリケーションレベルのチューニング
TCP 接続バックログ (backlog)
接続の受け付け待ちをいくつまで許すか。
通信タイムアウト
TCP 接続ができるまでの流れ
名前解決(IPアドレスの特定)
hosts ファイルの読み出し
DNS への問い合わせ
自IPアドレス、ポートの確保
SYNパケットの送信
SYN/ACKパケットの受信
ACKパケットの送信
参考