ISUCON5、紙一重の差で予選落ちする方法
福岡スレンダーズというチームでISUCONに初参加、そして予選落ちしてきました。 来年に向けての糧となるよう、良かった点、悪かった点をまとめておきます。 この通りにやると紙一重の差で予選落ちすることができます。
福岡スレンダーズ
- @mizoR @tkengo @monochromegane
- Web/モバイルのアプリケーションエンジニア(インフラ専任なし)
- 使用言語は全員が共通して触れるRubyを選択
- ベストスコアは約14,000。このスコアで終われていれば予選通過していたかも…
振り返り
良かった点
事前準備
- 環境構築は30分
- チューニングに専念するため、資産をGitHubプライベートリポジトリで管理する、各自の開発環境(エディタ等のdotfiles)を整えるといった環境構築はほぼノンストップでできるように手順化、スクリプト化しておいた。
- 事前に集まって当日の進め方を確認
- 過去問を解きながら当日どのように作業を進めるか(作業分担やチューニングの方針、ツールの使い方共有)を中心に確認した。
- 過去問を解く事は大事だが、同じ問題は出ないので各自の自習で補う。
- 経験者の話を聞く
- 全員が見れる大きなディスプレイあると便利、昼飯は事前に買っておくと便利などの情報は一回参加してからじゃないと意外と気付けないので助かった。
当日
- 普段やってることしかしない(できない)
- チームのチューニング方針
- ISUCON過去問を解いても普段の地力で予選突破ラインは出せていたので、本番でも普段からやってないことに手を付ける博打ではなくやれることを確実にやるようにした。
- 推測するな、計測せよ
- 基本中の基本。時間は有限なので闇雲に手をつけず、アクセスログ(kataribe)、スロークエリログ(pt-query-digest)を根拠に効果の大きいと思われる箇所から対処していった。
- 見える化
- 作業内容はGitHub+Slack通知で共有
- ER図をホワイトボードに書き出す
- 声掛け
- チームメンバが悩んでたら声を掛けて頭の整理を手伝い合った。
悪かった点
事前準備
- 特に無し。強いて言えばローカルベンチマークツールを想定してつくった結果通知の仕組みが無駄になったぐらい。
当日
- 司令塔役を決めておくとよかった
- 良い意味で全員まわりも見えるし実装もできるメンバーだったので前半は自律的に作業分担が進んでしまい、後半も自分で修正箇所を見つけて修正するの流れのまま進んだ。
- 結果的に各自の作業後、次の修正箇所を探すための時間ができ、継続的に修正を投入できなかった。
- 特に後半はベンチマークを実行、結果を元に次の修正箇所を指示する司令塔役を立てるべきだった。
- ベンチマーク -> ログ解析のリズムが悪かった
- 昨年までのローカルベンチマークを想定して各自の開発環境でベンチマーク->ログ解析を回す準備をしていたが、外部からのベンチマークになったことでサーバー上のログをどう共有するかを決めきれずに気づいた誰かがやるということになってしまった。
- 本来なら毎回のベンチマークごとにチューニングポイントが変わってくるはずなのに数回分間が空いたりしてリズムが悪いまま終わってしまった。
- 昼飯をきちんととらなかった
- 午前中、スコアが伸びず焦っていたこともあり、昼飯はおにぎり片手にひたすらチューニングを続けていた。
- 踏ん張りドコロの夕方頃、15分ぐらい集中力が切れた時間帯があったが今思うとあれはもったいなかった。
- 昼は外にいかないまでもちゃんと食べたほうがリフレッシュして午後望めたと思う。
ぐぬぬ案件
- 再起動テストでトラブル
- 終了1時間前に念のため行った再起動テストでISUCON5 本選出場者決定のお知らせにあるように再起動後rootボリュームがReadOnlyでマウントされてしまう現象に出くわしてしまった。
- このままでは運営側の再起動テストにクリアできないので最終のチューニングタスクを全て止めて原因究明&リカバリに注力。
- 最終的に開発用に立てていたインスタンスで再起動してReadOnlyにならなかったインスタンスを再登録。
- このインスタンスでのベンチマークが前回より下がるも原因特定には至らず…
チューニング一覧
チームのチューニング内容は以下の通り。
インフラ
- UnicornをDomain socket接続に変更
- 静的ファイルをNginxで返す
- Nginxのworker connectionを増やす
- Nginxのsendfile on, tcp_nopush on
- MySQL sort_buffer_size, innodb_buffer_pool_size の調整
- Unicornのworker processを1->4->8->6
- Nginxのworker processを1->2
アプリケーション
- relations(created_at), footprints(user_id), relations(one), relations(another), comments(user_id) にインデックス
- ログインページをエラーごとにRuby側でキャッシュする
- トップページ、自分宛てのコメント一覧の取得で不要なentriesとのJOINをやめる
- is_friend?によるN+1クエリを除去
- get_userによるN+1クエリを除去
- entries取得後使用されていないデータ整形処理を削除
- 友達のentriesを取得する際に不要なOR条件をクエリから除去
以上で13,000後半から14,000程度。
その他、entriesテーブルのbodyからtitle切り出しは思いついたもののALTERに時間かかりすぎて断念。 こちらの解決策を見て、さすがすぎる〜と唸る。
まとめ
ぐぬぬ案件はあったものの最終的なスコアは予選通過ギリギリだったはずなので方向性としては間違っていなかったかなと思いますが、やはり限られた時間を有効活用するために立ち止まらずチューニング施策を投入し続けるための体制にできたかどうかが紙一重、ただしとても分厚い紙一重の差となって現れたのかなと。
あとは地力を高めるためチューニングまわりの経験を勘ではなく根拠を元に進める経験をもっと積んでいこうと思います。
運営の皆様、こんなにも楽しいイベントを開催していただき、本当にありがとうございます!!そして、本当におつかれさまでした!!!
最後に、うちのチームが一番輝いていたときのキャプチャを貼っておきますね。
いや、ほんと参加してよかった。