ISUCON5のオンライン予選に参加してきました。 今回、初参加です。メンバーはDACに新卒で入社した、skryo(8年目),takusan(6年目),Tom-N@ck(3年目)で参加しました。 結果としては予選敗退してしまいましたが、Nodejsのサンプル実装が無くなるという大混乱からのスタートにもかかわらず、なかなか健闘できたのかなと思います。 最終スコアは12,700台でした。(正確な数字は覚えてないです)予選通過まであと1,000ちょっとだったので非常に悔しい。
やったこと
言語はRubyを選択しました
- 「/」のentries, entries_of_friends,comments_of_friends,friendsの処理を修正
- users,saltテーブルのマージ
- staticなファイルをnginxで返却など、nginx.confの修正
- my.cnf修正(innnodb_buffer_pool上げたりとか)
- ファイルディスクリプタの上限変更
- sysctl.conf変更
- nginx-unicorn間をunix domain socketに変更
当日のタイムライン
9:30~
集合。9:45くらいに11:00開始になったこと、そしてNodejsのサンプル実装がなくなったことを知る。 (混乱)
10:00
Nodejsの実装がなくなったことについて作戦会議。 過去問はすべてNodejsでやってきたので、基本方針としては、Nodejsで実装することにする。
11:00
各自環境構築を開始。
- 当初の作戦どおり、初期ベンチマーク取得。事前に用意していたnginx.conf,my.cnfを適用してベンチマークのアクセスログ出力、MySQLへのクエリログを出力する(Tom-N@ck) gzip圧縮をしていたが、cssのcontent-lengthがないって言われて、ベンチマークが通らず。 調査に時間がかかりそうだったので、gzip圧縮をやめてとりあえず、ベンチマークを通す。 クエリログはなぜかでない。。
- MySQLの各テーブルのレコード数を確認(skryo)
- アプリケーションの内容を確認し始める(skryo, takusan) すぐにNodejsに置き換えられるような量じゃないことに気づく skryo, Tom-N@ckがほんの少しだけRubyができるという理由からRubyを選択
12:30 対応方針について話し合い
nginxのアクセスログからボトルネックになっている「/」「friends」あたりから対応行うことで決定。 また、足あと、プロフィールをRedis化を行うことにする。 ※本来であればMySQLのクエリログの解析も行いたかったが、ある程度ボトルネックの特定ができたつもりになっていたので、クエリログが出ない件については一旦放置
各自の担当分けを以下のようにしてチューニング開始
- skryo: 「/」の処理をSQLチューニングを含め修正
- takusan: saltとuserテーブルをマージする対応、relationsにaccount_name,nick_nameカラムを持たせて、「/friends」を修正する
- Tom-N@ck: Redis化。Rubyでの実装がなれないため、まずはprofileのRedis化から着手。また、redis-serverをデーモン化する。
13:00
- 「/」の友達のエントリ、コメント取得の処理を改修(skryo)
- userテーブルに、saltカラムを追加&更新するddlを作成。user,saltをjoinしていた処理を修正(takusan)
- relationsテーブルに、one_account_name,one_nick_name,another_account_name,another_nick_nameカラムを追加&更新するddlを作成(takusan)
14:00
- entriesにユーザのaccount_name,nick_nameを追加しようと試みるも、データ更新のSQLが完了せず。。諦める。(skryo)
- 引き続き、「/」の処理をチューニング。友達数の取得処理を変更(skryo)
- 「/friends」のerb内で呼ばれているget_user処理をなくすため、改修に着手 logの出力がわからず、デバッグ方法がわからないことを共有しつつ、log出力方法をググる(takusan)
- 泣きながらRubyの実装を進める(takusan, Tom-N@ck)
15:00
- 「/」の自分のエントリ取得処理をチューニング(skryo)
- unicornのプロセス数を1→4に変更(skryo)
- ここでmy.cnfの設定が効いていないことに気づき、my.cnfを探す。(skryo)
- 読み込まれているのが/etc/mysql/my.cnfだということがわかり、/etc/my.cnfで上書きするもMySQL起動ができなくなる。(ここで30分以上はまる。。)
- log出力方法がわかったため、ソースコードの改修を行うが、Rubyの文法がわからず、if文がうまく通らず、投げやりになる 冷静に再度ソースコードを見直し、Rubyではコロンが特殊文字にあたることを突き止め、if文とerbを改修し、適用(takusan)
慣れないRuby実装がうまく進まない(takusan,Tom-N@ck)、MySQLも起動しない(skryo)、スコア全然出せない、の三拍子で若干あきらめムードが出始める (絶望)
16:00
- 結局MySQLが起動できない原因がわからず、ベンチマーク取得用の本番環境的なところで作業をしはじめる(skryo)
- ようやくMySQLパラメータの反映ができる(skryo)
たしか、ここらへんでベンチマークを取得。なんと1万超え(11000くらい)。たしか8,9位くらいにも入っていた気がする あきらめムードがだったが、全員一気にテンションがあがる (歓喜)
- profileのredis改修(Tom-N@ck)とfriends改修(takusan)を当てるが、ベンチマークが失敗。泣く泣く切り戻し。 終了間際にfriends改修に関して既存のrelationsにデータ追加された場合の処理(友達追加)を実装していないことが原因と判明。(もったいなかった)
- 上記通り、スコアがあがりやる気が出たので、実装をやめ、二人のサポート役(本番環境/ソース管理/ベンチ実行)にまわることを決意(takusan)
- /etc/sysctl.confに秘伝タレを適用(takusan)
17:00
- footprintsへindexを追加(skryo)
- MySQLのクエリログを出力し、他にも改善ポイントがないか洗い出しを行う。ここで、get_userの実行回数が多いことに気づく。(skryo)
- ユーザデータをredisに乗せてget_userの処理をMySQLではなくredisから取得するよう修正を開始(Tom-N@ck)
- 本番へのソースコード適用とベンチ実行&結果の報告を繰り返す(takusan)
18:00
- unicorn - nginx間の通信をunix domain socketに変更(skryo)
- この時間でのアプリ修正はリスク高いので、SQLのチューニングポイントを引き続き、調査(skryo)
- get_userのredis化が完了するもベンチマークエラー(Tom-N@ck)
- redisのエラー原因としてファイルディスクリプタが怪しそうだったので、やるのを忘れていた、/etc/security/limits.confに秘伝のタレを適用(takusan)
- 上記対応により、ベンチマークのエラーは解消されるもスコアが下がる
- 本番へのソースコード適用とベンチ実行&結果の報告 2重にベンチマークを実行するとスコアが分裂すつことを知る(takusan)
18:30
- 泣く泣く、2度目のRedis化を切り戻し(takusan)
- この時間での修正はリスクが高いので、nginx,unicornのプロセス数を変えてベンチマークを取ってみる(Tom-N@ck, takusan)
- 「Select *」をひたすらカラム名指定に修正(skryo)
- 本番へのソースコード適用とベンチ実行&結果の報告 サポートがサイトが重く、2重にテスト登録しないように、ブラウザと戦いベンチマークの登録を行う(takusan)
18:58
- 不要なサービス停止、全員ログオフして、最後のベンチマーク 12,700台をマーク (惜敗)
- 途中のスコアとか一切メモってなかったため、最後の正確なスコアもわからず。。いろいろ焦りすぎました
19:00 終了
感想
skryo いろいろありましたが、とても楽しかったです。(そして悔しい) とはいえ、最後まで冷静に対応できなかったのが反省点。 (ユーザデータは5,000件しかなかったので、わざわざRedis化させずにプロセスのメモリにキャッシュさせればよかった) 実際に参加してみて得られた反省点を活かして、また来年参加したいです(今度こそ予選通過したい) そしてまだまだ勉強不足であることを痛感しました。 運営のみなさま、本当にお疲れ様でした!
takusan 予選通過目標に挑みましたが、達成できず悔しかったです。 初めてisuconに参加して、自分のエンジニア力がどのくらいなのかを、客観的に見ることができてよかったです。 スコア的にも以外と頑張れたので、業務を通じて学んだこと、勉強してきたことが、間違っていないことを認識できた。 後は、過去問を通じて、チューニングポイントや方法を学ぶことができたのが僕の中でのかなりの収穫で、 業務でも必ず活きる知識を得ることができたことが、よかったです。 トップチームや予選を通過したチームとの差を考え、 エンジニアとしてのキャリアやスキルの方向性を考えるいい機会になりました。 とりあえず、node.jsでの参考実装を勉強がてら頑張ろうと思います。 ありがとうございました。
Tom-N@ck 運営の皆様、楽しいコンテストをありがとうございました! MySQLのパラメータチューニングでスコアが一気に上がった所で、アプリからミドル・OSまで幅広く見る事の大切さを実感しました。 目標の通過が達成出来なかった事が悔しいですが、リソースのモニタリング、 アプリのプロファイリングツールなど使い方を覚えた事が大きな収穫でした。 Rubyの実装でもたついてしまったので特訓して、来年こそ予選突破できるように頑張ります!