カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

「Tuningathon」2に参加してきた:やったことの備忘録と反省

第2弾!いろいろチューニングしてパフォーマンスを競うバトルイベント開催!「Tuningathon」2!! #tuningathon on Zusaar(以下チューニンガソン)に@mikedaさん(以下いけださん)と一緒に参加してきました。結果は7位入賞。色々反省点はあったものの、色々勉強になったので、そのメモでも。見た人が見たら、全然甘い部分も多々あるかと思いますが、晒しまする。

当日まで

まずルール。当日まで内容は分からず、公開されていた情報は以下のとおり。

  • 当日渡された環境を使い、OSやサーバ周りのチューニングでパフォーマンスを競います!
  • チューニンガソンの前提条件は、サーバ環境がAWS(EC2)でOSはAmazon Linux
  • AMIです。 チューニング対象はwebアプリです。 あとはまだ内緒です。
  • webアプリ自体の改変は対象外です。

ということで、何も分かんなかったんですが、何もしないのもイヤだったので、使えるものないかと物色&いけださんと連絡して、dropboxにやることメモみたいなのを置いて、二人で共有しました。
色々残しましたが、

  • Apacheは並列数しかスレッド立ち上げない
  • KeepaliveはOFFで様子見
  • PHPのプロファイラ、APC入れる
  • スローログ取得
  • dstat screen sysstatあたりは入れますか
  • コンパイルオプションメモ

という感じで、共有しておきました。

おはようございます

んで、当日(遅刻してごめんなさい)。。。
受付したら、以下のようなルールでチューニングすることを知らされたのでした。

  • wikipediaミラーの読み込み速度
  • 1並列で100回実行にかかる時間
  • URLは無作為抽出1000個からランダム
  • http_load -rate 1 -fetches 100
  • request/secの値がスコア

とのこと。最終的に4並列になりましたが、デカデータきたよぉと思ったのでした。squashfsの準備はしといたので、ファイル読み込みならそっちで行きたかったのですが、どうもそうは行かなかったw
んで、環境。

  • AWS ap-northeast-1
  • midium instance\*2
  • Amazon Linux 2011-02
  • インスタンス2個の使用方法は自由

そして、条件。

  • /var/www/html/mediawiki以下は改変NG
  • DBの内容は改変NG

とのことで、mediawikiって懐かしいなぁと思いつつ、いけださんと対策を練ったのでした。
二人で以下のようなことランチしながら考える

  • データでかいですねぇ
  • 絶対メモリ載らないですねぇ
  • キャッシュいけますかねぇ
  • まぁ、やれることやりましょー

という感じで、とりあえず中見てみないことには始まらないので、ある程度の構想は練りつつ、本番スタートであります。11:40からルールの説明があり、レギュレーションなどを聞いて、大体の内容を把握。そして、12時になったので、いざスタート。

いざ本番

とりあえず、最低限の環境がないとあとで辛くなるので、以下のことをやりました。

  • sshでログイン
  • 鍵置いてあったので、ローカルに持ってきて、iTermに設定登録
  • ssh_configでhost01, host02みたいな感じでIPの末尾でsshいけるよう設定
  • .vimrcいじる。→いけださんと同じユーザだったので、いけださんも自動補完とか急にされるので、迷惑かけるw
  • yumレポジトリ追加(epel, remi)

などなど。 以下、チャットログ抜粋(※名前はTwitterIDに書き換えました)

[11/10/01 12:13:07] masudaK: host74, host79で入れます
[11/10/01 12:17:32] mikeda: SELinux切る
[11/10/01 12:18:05] mikeda: ホスト名変える
[11/10/01 12:20:57] masudaK: ext4 32bit
[11/10/01 12:25:43] masudaK: epel
[11/10/01 12:25:46] masudaK: remi
[11/10/01 12:25:48] masudaK: 入れた
[11/10/01 12:34:39] masudaK: mysql> show variables LIKE '%slow%'

  ------------------------ ---------------------------------
  Variable\_name           Value
  log\_slow\_queries       ON
  slow\_launch\_time       2
  slow\_query\_log         ON
  slow\_query\_log\_file   /var/run/mysqld/mysqld-slow.log
  ------------------------ ---------------------------------

4 rows in set (0.00 sec)

[11/10/01 12:38:06] mikeda: IPV6も切っちゃいました
[11/10/01 12:44:17] masudaK: yum install dstat screen sysstat
[11/10/01 12:44:19] masudaK: 全部入れました
[11/10/01 13:16:06] masudaK: apacheめちゃモジュール読みまくってる…
[11/10/01 13:16:19] masudaK: /etc/httpd/conf/httpd.conf
[11/10/01 13:18:56] masudaK: とりあえず、APC入れますか
[11/10/01 13:42:50] mikeda: internalParse:1.8秒
[11/10/01 13:43:04] mikeda: replaceLinkHolders:1.2秒

チャットそこまで使わなかったかも。。。


まぁ、大体こんな感じで、お互い環境作ったり、デバッグしたり、コールの多いところのソース読んだりで、なんだかんだいって2時間近く経過。意外に時間かかったかもなぁ。

んで、手を打つ

ここまで状況として把握してたのは、以下の感じ。

  • mediawikiでページリンク?かなんかをすべてループで作成してて、リンクが多いページほど時間がかかる(mikedaさん、xdebug使いこなしてて感謝
  • APC入れたけど、ほとんど効果ない
  • その他モジュール削ったり、小手先のことやったけど、全然効果ない
  • スローログも一切吐かない
  • インデックス使ってないクエリもあっても一つぐらい。というか、アクセスしたらUPDATE走るmediawikiこえー。。。
  • 前段にプロキシ立てて、2台に割り振りは、このそもそも重い状態を解決しないと意味なさそう

など、アプリに手を入れられない上、割とチューニングするにも厳しい状況。

ベンチ用ファイルの作成

とそういえば、wikipediaのダンプファイル(8GBぐらいだったかな)とともに、ページ一覧のテキストファイル(約200万行)があったのを思い出し、もうベンチ自分たちで作っちゃえとなる(ここに来るまでがもう少し早かったらというのが今回の反省点)。

このテキストファイルには5フィールドぐらいあった気がして、3フィールド目がページのタイトル。なので、awkで抜き出して、それに全行URL付与するvimの使い方をいけださんに教わって、http\_loadで使うテキストファイル作成done。

(vimで行頭全てに http:~ を付与したかったんだけど、矩形選択してその後全選択分からず、困ったw

いけださんに教わったのは、「:%s/\^/ http:.... /gc」みたいな感じで\^を置換と、あとで矩形選択になったら、Gで末尾に移れるよ、と二つ方法教わってありがとうございますありがとうございます。)

2フィールド目が削除フラグだったようで、これで削除されてないページを除けばよかったというのも少し反省。なんかテストベンチで404を返すんだけど、ずっと原因分からなかった。あと、URLエンコードしてなくても大丈夫だったんだろうか。。。

更なる対策

んで、対策をしていくなうです。

まずPHP5.4

まぁ、CPUバウンドで結局PHPとapacheに一気に手を入れるかという感じで、前回チューニンガソンでパフォーマンスの良かったPHP5.4の事例踏まえ+自分でも前取ったベンチで5.4のパフォーマンスが良かった記憶があるので、5.4に入れ直すことに。あと、php-fpmでnginxも想定して、総入れ替えしようと決断。
このとき使ったビルドオプションは以下の通り。

./configure \\

--prefix=\$HOME/local \\
--enable-fpm \\
--enable-cgi \\
--with-mysql=/usr
--enable-mbstring \\
--enable-mbregex \\
--with-zlib=/usr \\
--with-zlib-dir=/usr \\
--with-gd \\
--enable-exif \\
--enable-ftp

今見ると、パスはひどいわ、何入れたいんだかちゃんとわかってないわで、とりあえず残念な部分が多すぎる。まぁ、ちゃんと事前にやっておけばよかっということでございます。あと、事前にphp -iでコンパイルオプション残して、状態を取っておかなかったのも反省点かな。


懇親会で@netmarkjpさんと話してたときに、「mediawikiのチューニングページにコンパイルオプション乗ってるよ」とか言われたときに、「まじかーーーー」となったのは言うまでもありません。

そのページはこちら。正確にはこの「PHP configuration」ですね。

nginx導入

まぁ、使ったことなかったけど、どっかで使ってみたかったので、ようやく出番という感じで導入。
コンパイルオプションはこんな感じ。

./configure \\
--conf-path=/etc/nginx/nginx.conf \\
--error-log-path=/var/log/nginx/error.log \\
--pid-path=/var/run/nginx/nginx.pid \\
--lock-path=/var/lock/nginx.lock \\
--user=nginx \\
--group=nginx \\
--with-http\_stub\_status\_module \\
--with-http\_ssl\_module \\
--with-http\_gzip\_static\_module \\
--with-http\_realip\_module \\
--http-log-path=/var/log/nginx/access.log \\
--http-client-body-temp-path=/var/tmp/nginx/client/ \\
--http-proxy-temp-path=/var/tmp/nginx/proxy/ \\
--http-fastcgi-temp-path=/var/tmp/nginx/fcgi/

公式サイトにyumのレポジトリ乗ってたので追加したんだけど、yumで入れようとしたらエラー吐いて、じゃいいやとコンパイルした次第。いけださんは普通にsearchできてたみたいなのに、僕が一人で暴走して入れてました。ほんとごめんなさい。。。

そして、フロントnginx,php5.4でバックがMySQL5.1という構成で、MySQLも入れなおして5.5にしたかったけど、コンパイルもdump流しこみも時間食いそうだし、5.5にあげてもそこまでパフォーマンスはあがらないはずなので、今回は他を優先。

MySQL周りもほんとはinnodb pluginとかで圧縮使ってみたりとか、色々できたかもしれないけど、5.1系と信じた。

ただ、Amazon Linux上に入ってるデフォルトのものが、ヘッダーとかライブラリのパスが慣れなくて、ちょいと苦戦したので、ここも反省点。すぐ見つけられないと。。。
(mysql_upgrde忘れててごめんなさい、使う勇気なくてごめんなさい、dump流しこみが絶対必要だと思っててごめんなさい)

nginx頑張れ

ここまでで構成的にはすっきりしてきたけど、ただnginxがmediawikiの「index.php?title="ページタイトル"」を「index.php/ページタイトル」にリダイレクトしてくれないので、いけださんがその部分のリダイレクトをしてくれる。

あとから聞くと、nginxでmediawikiが動かないチームもあったらしく、ほんと動いてよかった。いけださん感謝です。nginx完全にいけださんに任せてしまって、、、

この時点であと1時間ないか残り30分ぐらいになっていて、ダッシュでもう一台に同じ構成を作り上げる。うまく行けば二台構成でCPUバウンドになってる部分を分散できるので。ダメだったら、1台で行くしか無いと二人で決めて、いけださんはnginx、僕はなんとか時間内にPHP5.4インストールを目指し、最後の追い込み。レッドブルが欲しかった。

んで、残り15分ぐらいで大体環境ができて、chkconfigの確認と、またいけださんがrcでinit.dの処理を用意してくれて、マシン二台とも再起動させて、nginxとかphp-fpmの起動とか、mediawikiでエラー返さないとかの確認。問題なかったので、よしと思ったら、残り時間あとちょっとのところでAPC入れるの忘れていたことに気づくw

peclも全てないので、入れ直してバルスしたらいやだと思い、もう今回はしょうがないと開き直って終了。
これが最後のテストベンチの結果。

$ http_load -rate 4 -fetches 100 top1000\_all.list 100 fetches, 12 max parallel, 7.87196e+06 bytes, in 25.8125 seconds 78719.6 mean bytes/connection 3.8741 fetches/sec, 304967 bytes/sec msecs/connect:
2.02277 mean, 56.073 max, 0.428 min msecs/first-response: 1507.51
mean, 11558.5 max, 230.309 min 1 bad byte counts HTTP response codes:
code 200 -- 93  code 404 -- 7

404は単にページがないだけなので、3.8741 fetches/secまで行って、終了。
とりあえず、疲れたーです。

終わりに

最終的に結果は7位。2.95559request/secということで、3リクエスト行かなかったのが悔しかったなぁと。APCがないのにこれだけ捌いてくれて、nginx頑張ってくれたかもしれないけど、やっぱもうちょっと行ってもよかったのにーと思って、悔しかったでございます。

今回の反省点としては:

  • ベンチスクリプトはないなら、まず最初に作る。YSlowとかレンダリングの問題もあるし、curlじゃ並列とかしてないし、本番とほぼ同じ状況をすぐ作るべきだった。
  • mediawikiに関して、もう少しググッてもよかった。まず公式サイトはある程度見ませう。
  • 時間の使い方も考える。ソースいじれないのだから、ソース読む時間はもう少し短くても良かったかも。
  • コンパイルオプションとか、もう少し丁寧に。パスとか含めて、雑だった。@[methane](http://twitter.com/methane)さんがやったオプションとかを聞いたときに、PHPでの関数呼び出しの際に、デフォルトだとループでバイトコードを読みに行く?(ちゃんと理解できてなくてすいません!)ので、gotoで読み込むスピードを上げる設定があるので、そういう部分までちゃんと理解してやるべきだった。あと、

という部分とか、やっぱ深いレベルで理解してないので、勉強がそもそも足りない。

  • そういう意味でそこまで理解できないなら、remiとかからyumで入れたほうが良かったのかもしれない。
  • mysql_upgradeって手もあったが、忘れてた。使ったことがないなど。
  • 大事なときに使いこなせないで、未熟なものが多すぎた。nginxの設定とか、必要なコマンド(strace, dstat)とか、vimで一気に編集する方法とか。まぁ、普段からもっと深いレベルで勉強をやり直さないとと痛感。
  • あと、yumで入らなかったときとか、一人判断でコンパイルしてしまった。独断イクナイ。チームプレイで迷惑かけたかもなぁ。
  • ほんとにメモリに載せるの無理なのか、すぐその考えを選択肢から消してしまったのは良くないかもしれない。どう考えても、今回のルールに関係なくメモリに載せたほうが早くなるのは確かなんだから、「ほんとに無理なのか」考えても良かった。そういう意味で1位の人のアプローチは理に叶ってるし、すごいなぁ。とりあえず、常識ですぐ判断しちゃうと、劇的なことはできないですな。

ということで、足りない部分が多かったので、次に繋げられればと。

また懇親会も色々話せて楽しかったし、他の人の判断とかすごく勉強になったので、参加して良かったなと。そして、こんな暴走する僕と一緒にやってくれたいけださんありがとうございます!

最後に、主催のゼロスタートさま、会場提供してくださったVOYAGE GROUPさま、スポンサーのAmazonWebService, Gihyoさま、こういう素敵な機会を設けて下さりありがとうございました。
(チャラい言われて、いじられて、そこまで言われて勝てなかったらイヤなので、もっと勉強してやるんだw

特に某CTOには絶対次こそはw P.S. いくつか写真を撮ったので、公開。ブレた…


AJITO。こういう素敵なとこがさらりとあっていいなぁ。

夜はこんな景色が。オシャレですなー。

会場への道。中の写真は他の人に任せまする。

リス乱入。。。AJITOでの懇親会楽しかったし、めちゃ勉強になった。