12月16日の朝にFirefox 3.5.6がリリースされました。翌午前1時くらいにアメリカのからのアクセスが増え始めて、トラフィックが順調に2Gbpsを超えて、接続数が1万を超えそうで超えないところまでは見ていたのですが、気が付いたらトラフィックががくっと減っていました。下にトラフィックのグラフを示します。気付いたのは最初に落ち込んだ午前2時くらいでした。
下にHTTPの接続数のグラフを示します。接続数が急に跳ね上がるのは処理が滞っているからで、そのあと下がっているのはMozilla.orgのロードバランサ”Bouncer”が、サービスの停滞を検出して割り当てを一時的に止めているからです。
今回処理が滞った原因はCPUでした。下がCPUの使用率です。張り付いているわけではありませんが、ピーク時にはほぼ100%に達しています。
今回はTry&Buyプログラムで借りてきたSun Multithreaded 10 GbE Networking Cardを挿してありました。事前のテストでは、従来のGbEよりもCPUの負荷は低くなり、割り込みの負荷も8つのコアにきれいに散っていたので、CPUが問題になるとは考えていませんでした。海外の民間向けのトラフィックを任せているSINET線が2Gbpsしかないので、CPUの処理能力より先にそちらが埋まってしまうことを心配していました。
実は、CPUの負荷が問題になるとしたら、それがどのような形で起こり、解決するにはどうすればいいかはわかっていました。ネットワークカードが賢くなった結果として、それが起こるとは予想していませんでしたが。
CPUの使用率が100%近くまで上がったのは、worker MPMのスレッド間でロックが競合したときにスピンロックしていたからです。lockstatで調べたところ、Adaptive mutex spinの70%近くがcv_wait_sig_swap_coreで占められていました。これを呼んでいたのは、pthread_mutex_lockがロックを取りそこねたときに呼ぶシステムコールlwp_parkです。本当に処理能力が限界に達していたのではなく、ロックの取り合いで使用率が上がっていたのです。
マルチスレッドのプログラムで、スレッド間で共有しているデータを操作する際には、競合状態が生じないように普通はpthread_mutex_lockでロックして行います。しかし、CPUのサポートしているCAS (Compare-and-Swap)やLL/SC (Load-Link/Store-Conditional)といった命令を用いると、ロックせずに操作して、競合したら結果を破棄してやり直すことができます。この方法ではロックのためにシステムコールを呼ばなくていいので、圧倒的にオーバーヘッドが小さくなります。
worker MPMでも、一部のプラットフォームではロックなしの操作を用います。しかし、バージョン2.0系でサポートされているのはx86のLinuxとFreeBSDだけです。Apache Performance Tuningには、SPARCのSolarisもサポートされていると書かれていますが、サポートされていたのはわずかの期間だけで、ライセンスの都合で削除されています。本格的にサポートされたのは、APR 1.3.0が用いられるようになったバージョン2.2.9からです。
以前紹介したようにftp.jaist.ac.jpではバージョン2.0系を用いていました。以前からロックで性能が出なくなったら2.2系に移行しないといけないと思っていたのですが、そろそろ寝ようかと思っていたときに、そのときが来てしまいました。仕方ないのでバージョン2.2.14をコンパイルして入れ替えたのが午前5時過ぎです。すぐにCPUの使用率は下がりましたが、SINET線が埋まってしまったのでトラフィックは頭打ちになってしまいました。
しかし、いい加減欧米のFirefoxのアップデートを日本から支えるのも嫌になってきましたね。アメリカがピークの時間帯は、日本はサーバもネットワークもすいてるから問題ないんですが、何かあったときに対応できないのが嫌なんです。今回はたまたま起きていたから対応しましたけど。何かあったらBouncerがウェイトを減らしてくれますが、朝起きたらウェイトが半分になってたりするのを見るのは、あまりいい気分ではないんです。
Mozilla側がミラーの自動選択してくれないのなら、海外からのアクセスは
返信削除302(307) moved temporary とかで追い返して海外のサーバに誘導してはどうか
400req/sとかあるので海外かどうか調べるほうが大変なんですよ。
返信削除