念願のISUCONに初参加してきた。
チームメンバーは同僚のaskaさんとshiya氏で、「西日本世界チャンピオン*1」というチーム名で参加した。
予選までの準備
まずチーム名を考えるのに一ヶ月近く時間をかけた。最終的に満足のいくチーム名になって100万とった気になってた。
他には事前に準備しておいたほうがいいものや、どういう方針でやっていくかなどをチートシートとしてまとめて(githubのprivate repositoryで管理)メンバー内で共有した。これは当日も役に立ったので良かった。
特にshiya氏は普段objective-cを書いててサーバーまわりのことはわからないことだらけとのことだったので(しかも我々が選択する言語はPerlだ!)、事前に準備しておけばできるような作業(アクセスログ解析とかhttpdからnginxへの入れ替えとか)についてもチートシートにまとめておいて確認してもらった。
予選当日
まず心の拠り所として
を共有してた。これも共有しておいて良かった。
開始直後は予め決めていた進め方通りに進めた。
- 俺がAMIを起動して一旦みんなでそこへログインする
- 他の皆が環境やapplicationを確認してる間、俺が必要なもの(webapp, my.cnf, nginx.conf, etc...)をgitで管理できるようにしてprivate repositoryへpush
- デフォルトで動いてるrubyのアプリケーションを止めてperlで起動するよう変更
- 各種再起動スクリプト等を準備
- 環境が整ったらその状態からAMIを作成してチームメンバーに共有して、各メンバーはそのAMIを元にインスタンスを立ち上げて自分の環境で作業する
ここまでは割りとスムーズに進んだ。もちろんインスタンス起動直後にベンチマークを走らせてお約束の
暫定1位や!! #isucon
— ダメ人間 (@dameninngenn) September 27, 2014
をやってゲラゲラ笑ってた。
ちなみにベンチマークは比較がしやすいよう17時ぐらいまでは--workload 1しばりで行こうという方針にしてた。
各自確認した情報を口頭やIRCで共有しつつどこから取り掛かるか目星をつけていった。
- proxyからstaticファイル配信したい
- appへの接続をTCPからUNIX domain socketへ変更したい
- session storeをファイルからメモリへ
- memcachedいれとくかー
- 気まずいSQLたくさんあるのでなんとかする
- まず明らかindex貼ったほうがいいとこは貼る
- mypageでアクセスするたびusersからSELECTしてるけどどうかなー
最初挙げたのはこれぐらいだったと思う。
そこから各自これやるわーって言ってやり始めた。
俺とaskaさんはアプリケーションまわりとか気になったとこからやり始めて、shiya氏にはまずnginxの設定変更してstaticファイルをnginxから配信してもらうようお願いした。
リポジトリの運用ルールとしては、
- まずブランチを切って作業してそのブランチでベンチマークを走らせる
- masterにマージした時もベンチを走らせてスコアをタグとして記録
という風にした。途中から案の定ぐだったけど、ぐだった場合はこのルール気にせず本質的な対応に注力しようというのも共有してたので「おい!このマージスコアいくつやねん!!タグついてへんぞオラァ!!!!」みたいなケンカには発展しなかった。
で、ここまではわりかし順調やったけどここから雲行きが怪しくなってきた。
なんかしらんけど(←)ベンチマークのfailカウントが0じゃなくなった。
特に大した対応してないはずやのに突然。なんか変更加えるたびにベンチ走らせて確認してたはずやのに突然。
なんか記録してない意図せずやったことがあるんやろうけどhistory遡ったりcommitログ遡ったりしてみたけど全く改善しない。
masterとして扱っていたインスタンスでは同じgitのリビジョンでも再現しなくてほんとにわけわからん状態になった。
結論から言うともちろんなんかしてたわけで原因はあったわけやねんけど、それが判明した頃には既に2時間ぐらい経過してた。
askaさんがこれが原因じゃね?って言ってくれて「いやいやまさか、、、うわぁああああああああ」みたいに判明した。askaさんの時間も奪ってしまったしほんと死ぬしかない感じだった。
俺のしょーもないミスのせいでだいぶ時間ロスした……死にたい……
— ダメ人間 (@dameninngenn) September 27, 2014
いやいや違うんですよ。だって(言い訳は削除されました)
で、ここで完全に壊されて次の対応も何かハマって死にそうになって気がついたらえらい時間経っててご飯も食べてないから頭回ってなくて昼飯買いに行ったのが3時か4時ぐらいだったと思う。
そこから慌ててindex貼ったり、ログインに失敗したカウントはip基準とuser_id基準で別テーブルにしてそっちでカウントとってったほうが楽そうってことでそうした。
ここらへんでスコア13000(--workload 1)ぐらいだった。そういえばスコアの送信最初と最後のほうしかしてなかった。
ここで気づいたのが別テーブルにしたらinit時にダミーでinsertしてるデータ分も同様に最初に対応しとかないとダメってことでその対応もした。この初期データ対応は結構難航した。
failure_countを上のように別テーブルで管理するんじゃなくmemcachedとかでincrしてけばいいかなって話も出たけど、一度ログインに成功したらそこからのカウントを元々とるようになってたしmemcachedでincrした場合に途中でサーバー再起動かかってデータ吹っ飛んだら正しくカウントができないってことでその案は没になった。
一度BANされれば状態は変わらないけど失敗カウントが増えてる段階ではそのカウントも保持しておかなければいけない。
それ以降もなんかやろうとしてたけどベンチマークのfailが増えたりして中々うまくいかんくて気づいたら17時とかになってたのでそれなりのスコアで送信しとかないともうまずいってことに気づいた。
その時点でのmasterブランチは安定してなかったので過去のスコアがよさそうなブランチでworkloadの値変えながらベンチとった。
それでスコア30000ぐらいとかだったしまだやれることもあったけどどんどん時間がなくなっていった。
結局nginx.confとmy.cnfをいじってる時間もなくてほぼデフォルトの状態のままだった。my.cnfは予め準備してたサンプルのmy.cnfからコピペしつつちょっと設定いじったりもしたけど特にスコアに反映されるようなことはできなかった。
最後masterも安定した状態になったよってことだったのでそれに変更してベンチマークとった。
最終的に送信したスコアは33000ぐらいだった。
あの無駄にした2時間あればもうちょいなんとかなったかもっていう悔しさばかりが残ってるけどこればかりは仕方がない。
我々西日本世界チャンピオンはチャンピオンになれなかった。
最後スコア33000↑で時間内に送信したはずやのにグラフには30000のが残ったままやなーそういうもんかなーって思ってたら、どうやら最後のベンチはreportのcheckのとこでfailしてたようでそれに気づいてなくてそのまま提出してしまってた。後日提出したAMIからインスタンスもっかい立ち上げてベンチマークとってみてその時気づいた。もう死ぬしかない。
今回の失敗によってISUCONを戦ううえで大事なことがわかった。
ご飯は食べよう。
本選に出場できないのはほんと悔しいけど初めてのISUCON予選すごく楽しかったので運営の皆様には感謝するばかりです。
本当にありがとうございました。
*1:うめぼしの謎読みましょう Amazon.co.jp: 蔵出しうめぼしの謎完全版 (ダイトコミックス): 三笠山 出月: 本