続・間違いだらけの負荷対策

事の始まり

3月に入ってから「斉藤さん」のWebサーバーのピークタイムでのアクセス数が秒間180アクセスを境に動かなくなり、しまいには一部アクセスが固まって動かなくなるという現象が発生した。

Apacheのエラーログを見ると、データベースサーバーに接続できていない旨が出ていたため、その辺を念頭に置いていろいろと探ってみたのだが・・・。

ソケット数の限界?

netstat -ant」と打つと、その時点でのTCPコネクションの一覧が出る。
ピーク時にWebサーバー側は30000前後、DBサーバー側は8000前後。
HandlerSocketのポート(標準では9998と9999)に絞ってみてみると、Webサーバー側は8000前後なのに対し、DBサーバー側は500前後。
明らかにWebサーバーのコネクション数がおかしい。
MySQLのコネクション数は問題なさそうなので、HandlerSocketのソケットが開けなくてパケットがドロップしてる?と想像して、/etc/sysctl.confにいろいろ設定を書いてみるが駄目。

iptables

そういえばカーネル周りの設定をしておきながらカーネル周りのログを見ていなかった、と思い/var/log/messageを見てみると以下のようなログが出ていた。

Mar  8 02:57:26 api kernel: ip_conntrack: table full, dropping packet.
Mar  8 02:57:38 api kernel: printk: 346 messages suppressed.

これを元にググってみると、どうやらiptablesに関係するエラーらしいということが分かった。
ちなみに、ニフティクラウドのサーバーは建てた時点で外部ネットワークに晒されるようになっているため、iptablesによるポートフィルタリングがデフォルトで設定された状態*1である。
この、iptablesはパケットを解析する際に/proc/net/ip_conntrackというファイルにその情報を記録するのだが、テーブルの上限数が設定されており、それを超えてしまうとパケットを落としてしまうらしい。
現在のiptablesのテーブルの項目数(?)とその限界は以下のように確認できる。

# 最大
$ cat /proc/sys/net/ipv4/ip_conntrack_max
65536
# 使ってる項目数
$ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count
63642

うおおおおテラギリギリスwwwwwwww
というわけで、そいつを上げればいいんだなと思い、両方のサーバーの/etc/sysctl.confに

net.ipv4.ip_conntrack_max = 131072

を設定してApacheBenchを動かしてみると、今まで途中で止まっていたベンチがスムーズに動くようになった。

まとめ

  • それなりのアクセスがあるWebサーバー・DBサーバーではiptablesがネックとなる場合がある。
    • サーバー建てた時点であるいはアクセス数が増大してスケールアップした時点で、「net.ipv4.ip_conntrack_max」の設定をチェックすべし。
    • 目安は搭載メモリ数(MB)*64くらい

もしかして・・・

(アクセス裁けなかったの)Nginxのせいじゃない・・・!?

*1:デフォルトでは22(つまりSSH)だけを許可する設定だった気がする