午後から→オーバークロック

駆け出しハッカー()によるプログラミング・サービス開発備忘録。

ISUCON予選を学生枠でギリギリ通過する技術

友人に書けと言われたので書きます。

僕(nemupm)は今回ISUCON5に、shiki,itkqと一緒にアジ・タコ・エンガワ!というチーム名で参加しました。
(チーム名は各々の好きな寿司ネタです。もちろん僕はエンガワ派です。)
結果、6566点で学生枠5位という滑り込み通過で、奇跡的に本戦に出場できることになりました。

実は僕は去年もshikiと二人で参加したのですが、予選であえなく惨敗したので、取り敢えずリベンジ出来て嬉しいです。
今回僕はインフラ側(アプリ以外)を任されていたので、準備したことおよび本番で行ったことなどをつらつら書こうと思います。

準備

去年ISUCONに出場してみて感じたことは、

  • チューニング手法について知識が足りなさすぎた
    • チューニングと聞いても、SQLの改善とかデータをオンメモリにするとかそういうことしか思い浮かばなかった
  • ボトルネックの分析が雑
  • 準備8割

ということでした。
そのため、最低限準備として以下のタスクはこなそうと考えました。

  • どんな問題に対しても使える一般的なチューニング手法は可能な範囲で網羅する
  • アクセスログ、スロークエリの分析はすぐ行えるようにする

そして、先人たちのブログを読みながらチームメンバーでISUCON4の予選問題を解きました。
結果わかったのは、

  • チューニング手法だと
    • カーネルチューニング大事そう
    • unix domain socket
    • my.cnfのチューニング
    • innodb_buffer_pool_sizeとか
    • nginxのチューニング
    • nginxでの静的ファイルの配信
    • nginxでSSI
  • my.cnfには読み込み順序とかあるらしいぞ、気をつけろ
  • ps auxして怪しいプロセスないか確かめろ
  • kataribeさんつよい
  • pt-query-digestさんもつよい
  • top!dstat!iostat!

ということでした。
あとはこれらをgithubwikiにまとめて本番を迎えました。

本番

僕の想定が完全に甘かったのですが、
サービスがsupervisordじゃなくてsystemdで管理されていて、
最初無駄な時間を食ってしまいました。(本当申し訳ない)

ここで他の二人がアプリのソースコードを読んでくれたところ、どうやらISUCON4予選の比じゃないくらいアプリが大きいようで、
事前に打ち合わせしていた策だとフレームワークを外す予定だったのですが、急遽予定を変更することにしました。
(訂正:あとで聞いたらそもそもフレームワーク使われていなかったというオチ)

その後なんとかアプリをGolangに変えて、Failするバグも直してベンチマークを走らせるとスコアが700くらい。
ここから、kataribe・pt-query-digest・topとかでボトルネックを調べながら作戦を立てていきました。

調べた結果、明らかにクエリがボトルネックだったので、アプリ側の二人が、relationsをオンメモリ実装することに決まり、 (Redisとかではなくて、DBのデータを初期化時にgoの変数に突っ込んで、SQLの処理を変数の処理に置き換える) その間はちまちまと準備した設定を反映させたりrelations以外のインデックスを作成したりしていました。

結果、700->1500くらいに。 (あんまりスコアを覚えていない) 途中my.cnf反映されない問題(結局かい)との格闘や、entries重すぎじゃね問題などで時間を食ってしまったため、
この時点で時間が半分は経ってた気がするので、ランキング上位陣がどんどんと点数を伸ばしているのを見ながら、
「全然スコア伸びねえじゃん。やべえよやべえよ、準備した策使い切っちゃったよ」と焦っていました。

ここで自分もソースコードを読んでクエリの書き換えなどができたら良かったのですが、
自分だけSkype参加だったこともあって他二人と密に連携を取れるわけではないため、
邪魔をしては本末転倒だということで、 オンメモリ実装が終わるまではMySQLのキャッシュの有効化とか圧縮テーブルの検討(結局やらなかった)とか
ちまちま設定を変えたりペヤングを食べたりしていました。

そんなこんなでいつの間にか17:30くらいになっていましたが、ついにオンメモリ実装が終わり、
その状態でベンチマークを走らせたところ、一気にスコアが7000台にアップ。
あまりに驚いたため思わずSkype越しに叫んでしまいました。
その後色々調整して、最終的にスロークエリログを見ても全て0.01s以下に収まっていたようなので、
SQLは大分改善されたかなという印象(もちろんクエリを書き換えたりしてもっと改善できるところは多々あったようですが)。

その後、再起動したらスコア下がる問題などでかなり焦りましたが
innodb_buffer_pool_dump_at_shutdownとかOnにするべきだった?)
ベンチマークを繰り返してなんとか6566まで回復した時点で試合終了。
今回学生組が35組もいたこともあって予選通過は難しいかなーと思っていましたが、
本戦に行けることが判明してまたも驚き。
そんな感じで今に至ります。

反省

  • アプリ側を他二人に任せすぎて、特に後半あんまり貢献できなかった
  • gitも正直詳しくないから他二人に任せていた
  • 後で他のチームがProfilerDrivenDevelopmentとかやってるのを知って、プロファイラとか本番前に使ってみたらよかったと思った
  • SQLのこと知らなさすぎ
  • そしてやっぱりボトルネックの把握が雑

今回は二人の実装のおかげでなんとか予選通過できたので、本戦こそは貢献したい!
(なおitkqとはSkypeでしか話したことがないので本戦で初顔合わせの予定)