TCP Fast Open
TCP Fast Openと呼ばれる技術があり、RFC 7413として標準化されている。
このTCP Fast Openを使うと、一度コネクションを貼った相手とは、TCPの3ウェイハンドシェイク中にデータを送受信できるようになる。クライアントからSYNとともにデータを送信することで、実際にデータを送受信開始するまでの待ち時間が短縮できる。
TCP Fast Openの闇
しかし、数年前よりこのTCP Fast Openには一部のネットワークで奇妙な振る舞いをすることが知られている。Appleの人が実際にデプロイした時に見つけたもので、IETFやNANOGにて報告されており、その時の資料は下記のとおりである
(0.1%の環境で発生したと発表時の質疑にもある)
一部を抜粋すると
TCP Fast OpenのSYN, SYN/ACKは通るが最後のACKがブロックされる
3ウェイハンドシェイクは完了するが、片方向のみデータ送信に失敗する
この状態になると、OS的にはハンドシェイクが完了しておりタイムアウトを待ち、その後アプリケーションなどにより再送信されるという繰り返しになりうる(フォールバックされない)。
この問題はクライアントの居るネットワークのファイアウォールやIDSが原因であり、単純にはサーバやクライアントでTCP Fast Openを無効にするという対応をすることになる。
Kernelでの緩和対応
上記問題を緩和するために、Kernelに「net/tcp_fastopen: Disable active side TFO in certain scenarios」というコミットが入った。
基本的には、クライアントサイドにてTCP Fast Openを使ってる時に怪しい挙動があった場合は、globalにTCP Fast Openを無効にする。最初はデフォルトで1時間無効化し、次に失敗したときは2時間と倍々で時間が長くなっていく仕組みになっている。通信に成功した場合は、待ち時間は最初の1時間にリセットされる。待ち時間は、tcp_fastopen_blackhole_timeout_secで設定することも出来る。
globalに無効になるのは、クライアント側のネットワークが原因であることが主なので、全体として向こうにしたほうが良いということだろう。
また怪しい挙動とは
- クライアント側でTCP Fast Openを利用しており、データが無く、順序が正しくないRSTを受信した時
- クライアント側でTCP Fast Openを利用しており、順序が正しくないFINを受信した時
コメントを読む限りサーバ側では現状特別なハンドルはしないようだ。大きいサービスだと、TCP Fast Openを有効にするには上記コミットが普及してからの方が良いのだろうか...(TCP Fast Openが悪いってわけじゃないんですけど)