κeenのHappy Hacκing Blog | Lispエイリアンの狂想曲

#ISUCON 4 予選に学生枠で参加してきました

κeenです。ISUCON 4 予選に学生枠で参加してきたのでレポートです。日曜、2日目の方に参加です。

メンバー集めと準備

一番苦労しました。去年と同じく、全く知らない人と組んでます。全然集らなくて、@941さんがメンバー集めの音頭をとってくれたりして、ようやく集りました。941++。

結局ISUCON夏期講習にいたPythonアイドルのくーむ(@cocodrips)さんとその友達の友達のねむねむ(@nemunemu3desu)さんと出ることになりました。くーむさんは競技プログラミング系Pythonista、ねむねむさんはプログラマのためのWebサービス開発のバイトをやってるWeb系Rubyist。因みに私は去年もISUCONに出て学生賞なんか貰ってるのでISUCONで要求される技術は一通り、広く浅くといった感じのRubyist。普段はLisp書いてます。「Lispを書く」はダブルミーニングですよ。すごいどうでも良いけどくーむさんは情報系のM2、ねむねむさんは情報系のB4、私は数学科のB4です。

流石に初対面のメンバーでいきなり競技を始めても何も出来ないので一度3人で顔を合わせて打ち合わせをしました。簡単に書いてますけど待ち合わせとか苦労したんですよ。

  • データ量とかアルゴリズムに対する感のあるくーむさんにはMySQLのチューニングを任せる
  • くーむさんは各社のインターンで実務経験があるのでデプロイとかのコードの流れ、ベンチマークの管理もやって貰う
  • その周辺のツールも作って貰う
  • Rubyでwebサービスの開発をやってるねむねむさんにはRubyのコードをがんがん弄ってもらう
  • Redisを使うことも視野に入れてもらう。Redisの経験はあるようなのでそんなに問題なさそう。
  • あとは余ったNginX、Varnishをκeenが担当する
  • 恐らくNginX、Varnishは然程手間取らないのでアプリとMySQLで苦戦してる方にκeenが入る
  • 最初のセットアップはAWSアカウントを作ったくーむさんにやって貰う
  • 最初に計測することが大事なのでデフォルトのままログの設定だけ変えてベンチを走らせて作戦会議をする
  • チーム名は3人のアイデンティティを合わせて「(ρ_-)/超銀杏バスターズ(・ω・ o)」とする

あたりを決めました。

くーむさんは完全に普段とドメインが違うのでちょっとつらそうでしたがSQLとかRedisとかの本を貸したらめっちゃ勉強してきたみたいでした。 流石、情報科ですね。地力が違いますね。あとはGithubの学生が使えるプライベートリポジトリを用意してくれたり。ベンチマークを走らせたら時刻とgitのコミットIDをセットにしてログ用のレポジトリに突っこむスクリプトの準備もしてくれました。

ねむねむさんはAWSアカウントを作って去年の予選の問題を予習してきたようでした。あとRedis使うかもって言っといたらRedis in ActionのPDFを見付けてたようなので読んできたんじゃないかなと思います。Rack用のプロファイラを試したようでした。去年も使おうとして結局使えなかったminiprofiler。ねむねむさんにも使えなかったようです。

私はApacheとかNginXのログフォーマットを整備してパス/メソッド毎の(合計)レスポンスタイムを出す集計スクリプトを用意。その他マスタリングNginXを一通り読み直したりOpenRestyでmemcachedやlua、Redisのプラグインがあることを確認してインストールスクリプトを書いたりしてました。Varnishは間に合いませんでした。

当日

開始

LINEカフェを使わせてもらうので9:20に集合。ちゃんと集まる。家の近いくーむさんがデカいディスプレイを持ってきてました。

LINEカフェではLINEインターンの経験のあるくーむさんが勝手が分かってるので机を勝手に動かして三人横並びに座る。真ん中にくーむさんの大きいディスプレイがきて良い感じでした。

10:00に号砲と共に競技開始。早速3人ともAWSの初心者でAMIの起動の仕方が分からず詰まります。ここクリックしてみて?とかいいながらログイン出来たのが10:20くらいですね。isuconユーザーにRSAのpubキーを突っ込むもパスワードを要求されてハマる。くーむさんはLinuxには不慣れなようだったので私がやるも夏期講習のときと同じく解決出来ず。うーん。結局パスワードのまま通しました。

gitの設定をするときにアプリとログはレポジトリを分けることは決まってましたがログを吐く場所を決めてなかったのでゴタゴタ。/var/logに吐こうとするもMySQLが吐いてくれない。権限の問題じゃね?とか言って777にするという邪悪なことをするとねむねむさんがsshを締め出される。MySQLが吐いてくれなかったのは再起動忘れ。sshを締め出されたのはsshdのログファイルの権限の問題。この辺解決したのが11時過ぎかな?

ごたごたしてる間はねむねむさんはアプリ読んでくーむさんはインテグレーション周りの準備してくれたり。私もちょっとアプリ読んだりエラーでググったり。

作戦会議

12時前なので昼御飯食べながら。

  • ベンチマークを走らせると明かにMySQLが重いのでインデックスを張る(くーむ)
  • アプリはキャッシュ効きそうなのでガンガンRedis使う(ねむねむ)
  • とりあえずNginXの最適化とVarnishは入れる(κeen)

な感じです。

作業

Typoがあった以外はNginXとVarnishはスムーズに。

実際にはくーむさんがログの自動プッシュ周りで苦戦してたのでけんちん汁を食べてる隙に私がインデックスを張ることにしました。ちまちまexplainしながらやるもどうもうまくいかない、と思ったらinit.shのヒアドキュメントが二重になってる…。そこを解消したら一気にスコア上がりました。でもWHERE狙いとORDER BY狙いってどうなんだっけとなって多少過剰なインデックスだったかもしれません。

それでもうMySQLはCPU使わなくなったのでワークロード上げてみたらスコア12,000くらいになりました。

なんか静的ファイルでベンチマークエラー出てるとくーむさんから報告がありました。Varnishの設定ミスったかなと思ったらエラーメッセージが無機質だったのでシステム関連っぽい。そこは全て独学でやってきた数学科生のググり力を発揮。調べるとローカルポートを使い果たしていた模様。システムの設定をコピペ。エラー出なくなる。

RubyがCPU使ってるのでNginXからのリダイレクトをunixドメインソケットに。あんまり効果無し。

ねむねむさんのRedisキャッシュ化が入って15,000とか。ねむねむさんを信じて「キャッシュして」とだけ言っといたので詳細は不明ですがユーザーはRedisに全部突っ込んだ模様。その後は脱MySQLを目指して黙々と作業してました。

私は/reportがN+1クエリなので直そうと2時間くらい奮闘。後にスコアには反映されてないことを知らされて絶望。よく見とけば良かった。しかもEmacsのバッファに残ってるものをコミットしてしまってねむねむさんのコミット上書きしてしまったりしました。

まだRubyがCPUを使ってるのてテンプレートエンジンを置き換えることを考えました。slimが速いと風の噂で訊いたのでくーむさんにお願いしてみるもスコアがた落ち。あれRuby製だったんですね。C製のテンプレートエンジン捜しとかなきゃ。

さらにくーむさんがCSSやpngのminifyを試みるもチェックサムをとられていたようで失敗。良く見たらMD5とるってレギュレーションに書いてありました。後にminifyでなくインライン化すれば良かったらしいと聞く。

最終確認とか

17時あたりで一旦chkconfigしてリブートしてもベンチが動くことを確認。よかった。一応AMIを作ります。その後でN+1クエリの解決が動くも当然スコアには変動なし。あとはミドルウェアのログを切って脱MySQLは間に合わなくてアプリの微改善が入りパラメータの微調整をし、17,700あたりで競技終了。

終わってみて

一応2日目の中では学生1位なものの、1日目10チーム、2日目4チームなので何とも言えないですね。一般枠は40,000でも本戦出場無理ポとか言ってるのに20,000にも全然届かないスコアで本戦出れるかもとか言ってるゆとりの学生です。

反省は

  • レギュレーション良く読む
  • ベンチマークのスコアリングも確認する
    • 静的ファイルは0.1点と思ってたら0.01点だった。この差大きい。
  • 権限管理は適切に
  • hangoutに思ったことを垂れ流す筈だったのに口頭で済ませてしまった
    • それだけならまだしもhangoutに貼ったものが無視されてしまった
  • プロファイラ使えるようにならないとね。
    • RubyがCPU喰ってるのは分かってるのにどこがまずいか分かんなかったのは悔しい
  • 深みに嵌ったらあきらめる
  • ブランチ切るとミドルウェアの違いで問題が出る(varnishとnginxの80の取り合い)
  • 互いのスキルを把握しておく
  • 開発スタイルを決めておく
  • workload、workerprocessは最適値を捜す(コア数が4だったので4~8で決め打ちだったけど後に30くらいまで上げれると聞く)

かな?私が普段Linuxを使ってるのでLinuxの設定くらいみんな出来ると思ってたら私以外Macerだったってのは予想外でした。本来なら私がAWSアカウント持ってれば問題なかったんですけどクレジットカード持ってないんですよね。つらい。

開発スタイルはねむねむさんがpull-reqスタイル、私が細かいコミットをマスターに入れるスタイルでした。設定ファイルとアプリの違いもありますがpull-reqスタイルの方がロールバックし易いしそっちに統一した方が良さげですね。

個人的に、いつも通りケアレスミスが多かったのは反省しなきゃなと思います。「あれ?動かない。あ!そうか!」みたいな。メンバーは「すげー。デバッグ速えー」って言ってましたけど違いますよ?世の中の不当評価はこうして産まれるんだと少し社会を知りました。

Varnishももうちょっと使い熟さないとなーってのとlua勉強しなきゃなーってのが個人的な本戦に向けた準備ですね。N+1のとこはSQLの練習が出来たので個人的には満足…って言ったらメンバーに怒られますかね。

全体として、チームは上手く動いてたんじゃないかなと思います。N+1のところで無駄に嵌らずにねむねむさんと2人でアプリの改修やってたら脱MySQLが間に合ったんじゃないかなってのが心残りです。インテグレーションはくーむさんのスクリプトで良い感じだったのでもうちょっと改良して本番にも使いたいですね。あとCapistranoかFabricも準備しないといけませんね。

本当、やらかしてばっかの私に怒ることなく一緒にやってくれたくーむさん、ねむねむさんには感謝してます。もし予選通ってたら本戦も宜しくお願いします。

そして忙しい中ISUCONを開催して下さったCOOKPADの方々、941さん、ありがとう御座います。ベンチマーカーの問題にも迅速に対応して下さってこちらは本当に楽しく競技出来ました。

P.S.
今回の作業レポジトリはここ、ログレポジトリはここにありますがまだ非公開です。そのうち公開されると思います。

Written by κeen