LVS が FIN を落とす
ちょっと前に、Webアプリの Load Balancer として、LVS(Linux Virtual Server) を DR (Direct Routing) 構成で用いてみました。LVS はオープンソースの LB。BIG-IP など使うと安くても数百万円コースですが、LVS なら安いサーバ 2台で Active-Standby な LB を組めます。DR は、クライアントへのレスポンスを LB を通さずに返す方式。NAT 方式だと行きも帰りも LB を通りますが、DR は行きだけなので、LB がスループットのボトルネックになりにくいという長所があります。その代り、設定はちょっと手間がかかります。
<p>だいたいうまく動いていたのですが、ある月曜日に突然、社内からアクセスすると、だんだんと動作が遅くなって、しまいには自社のプロキシが「サーバが反応しないからアクセスできないよ」という趣旨のエラーを返し始める、という問題が出てきました。</p>
<pre>
Webアプリと社内ネットワークの概要
DB - Web - LB - Router — Internet — Router - Proxy - Client
</pre>
<p>時間に追われながら、調査を開始しました。まず、週末に、社内のHTTPプロキシサーバが置き換わり、処理能力がパワーアップしていました。前の週との間で変わったのはプロキシだけなので、とても怪しいのですが、プロキシの何が悪いのか、まったくわかりません。</p>
<p>社外からアクセスすると通常の速度なので、Webアプリ側の処理には問題なさそうです。サーバの Load Average も余裕あり。Webサーバ上の tcpdump で調べると、Webサーバからクライアントへ ACK を返すタイミングが変なことがわかりました。一通りの HTTP request - response が終わったあとに、ちょっとの空白時間を挟んで、まとめて ACK が返ります。謎。目処が立たないので、別の対策でしのいで、サービス正常化を優先させることにしました。</p>
<p>それからしばらく後の再調査で、Webサーバで FIN_WAIT_2 が大量発生していることが判りました。TIME_WAIT がたくさんなら普通ですが、FIN_WAIT_2 の多発は何かありそうです。</p>
<p>tcpdump で各所のパケットをキャプチャし、丹念に動作を追うと、LVS がクライアントからの FIN を落としているために Webサーバに届いていないことが確認できました。ググると、LVS の DR 構成は、帰りのパケットが LVS を通らないために netfilter(iptables) がコネクションの確立を認識せず、FIN を通さないということが判りました。netfilter で TCP の state を見ないようにすることで、無事解決です。</p>
<pre>
> For one of my dozen of services ( a straight TCP connection), the
> TCP-FIN packets that are arriving on the load balancer are never
passed
> to the real server.
Basically, all packets (SYN and non-SYN) are allowed by the “–state
NEW” iptables but not by the ESTABLISHED,RELATED, because the director
never sees the replies from the real server and so never creates a
conntrack for that connection.
When a FIN packet arrives, it is not validated as a –state NEW,
because
it’s flag FIN is activated and so, that particular packet is dropped.
(snip)
So the solution is to change the iptables rule from
-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport $VPORT -j ACCEPT
to
-A RH-Firewall-1-INPUT -m tcp -p tcp –dport $VPORT -j ACCEPT
http://archives.free.net.ph/message/20080425.113313.b51288d0.ja.html
</pre>