net.ipv4.tcp_tw_recycle は NAT の内側からの SYN を落としてしまう
NAT の内側にある複数のウェブサーバから外部のとある API サーバを叩いた時に、SYN_SENT ステータスのままになる(SYN/ACK が返ってこない)事があります。
特に混雑時間帯に顕著化します。
他のネットワークからは問題がないことと、同じ NAT の内側にいる別の忙しくないサーバからは現象が出ることから、そのネットワークの NAT あたりを疑っていましたが、どうも調べていくと Linux の設定と実装の問題のようで。
TIME_WAIT ステータスを早く回収するために net.ipv4.tcp_tw_recycle を有効にするというサイトをよく見かけますがこれが罠で、同一 IP アドレスから送信された TCP パケットのタイムスタンプフィールドを見て、60秒以内に古いものが来たらそのまま捨てられてしまいます。
本来の P2P なネットワークなら問題ありませんが、NAT の内側に複数のサーバがいる場合は NAT がタイムスタンプを書き換えない限り、タイムスタンプが増加することを保証できません。
クライアントの環境が特定できないサービスでは使うべきではないでしょう。
これの消極的な解決方法はこちら側で以下を無効に設定をして、TCP タイムスタンプを使用しないようにします。
FreeBSD: net.inet.tcp.rfc1323
Linux: net.ipv4.tcp_timestamps
以下が参考になります。
kernel: TCP: time wait bucket table overflow の解消とTIME_WAITを減らすチューニング
気ままにインフラエンジニア
ただし、サーバ側で net.ipv4.tcp_tw_recycle が有効で、クライアント側でTCPのタイムスタンプオプションが有効(Linuxの場合net.ipv4.tcp_timestamps = 1)だと、NAT/LBを超えたときにSYNを落としてしまい、接続障害になる。 ユーザー向けに使っているとSB携帯などで障害が発生してしまうようなので、使わないほうがいいかも。
2007-05-21
LowPriority
この処理により、同一IPから60秒以内に前回のTCPセッションの最終パケットより前のTCPタイムスタンプを持ったSYNパケットが来ると該当パケットを落としてしまう。
Linux kernel のソースを見てみたところ、確かに tcp_ipv4.c に当該箇所がありました。
やはり mohta 先生の言葉通り NAT が悪でしょうか……。
と思ったらなにやら新しい End to End NAT なるものの記事を見つけました。
そうですか、mohta 先生が NAT を考える時代になりましたか……。
ディスカッション
コメント一覧
まだ、コメントがありません