linux の TCP_DEFER_ACCEPT (サーバサイド) の挙動について

以前 (2.6.31 まで?) は以下の挙動*1

  • 最初のペイロードを受信するまで SYN_RECV ステート
    • クライアントの ACK (TCP ハンドシェイクの最後のパケット) を受信していたとしても、SYN-ACK を送り続ける
    • 190 秒たったら、サーバ側は TCP 接続確立失敗と認識
      • クライアントは SYN-ACK を送ってるから接続できてるつもり

TCP の仕様的にどうなの、って話はわかる。ただ、IP 層はパケットロスの可能性があるわけで、インターネットを使っていて、この挙動で問題があるとしたら、それはアプリケーションのバグだと思うけど。一方で、 LAN 上でパケットロスが (ほぼ) 起こらない前提で作ってたら困ることがあるのかなー。UbuntuBTS で話が出てるのは、そういうケース (特定のハードウェアロードバランサと TCP_DEFER_ACCEPT を使う Apache との相性問題)。

で、TCP_DEFER_ACCEPT の挙動は 2.6.32 で、こう変わった。

  • TCP ハンドシェイクの ACK を受信したら、もう SYN-ACK を送り続けないように
  • 190 秒たったら、SYN_RECV => ESTABLISHED にステート変更
    • アプリケーションの accept(2) にソケットが渡される?

参考:
Bug #134274 “TCP_DEFER_ACCEPT causes random HTTP connection fail...” : Bugs : apache2 package : Ubuntu
Linux 2.6.32-rc6 [LWN.net]
netdev - [PATCH] tcp: reduce SYN-ACK retrans for TCP_DEFER_ACCEPT

*1:CentOS 5.4 (2.6.18) で軽く試してみたけど、確かにそれっぽい