オンラインで開催されたISUCON4予選(1日目)に、同僚でフロントエンドエンジニアの@itoKami1123さんを誘って2人で参加しました。
チーム名は「キャム☆マックス」です。

言語はRubyを選択して、最終スコアは20835でした (workload=5)

 

当日までの準備

  • 過去問題(ISUCON3)を実際に2人でやってみた。
  • 1ヶ月間くらいかけて昼休みの時間を利用して以下を勉強
    • ISUCON3のソースコードリーディング
    • ISUCON3の解説ブログを読む
    • MySQL(インデックスと実行計画まわり)
    • Ruby(入門)
  • 事前に公開されたレギュレーションをよく読む

 

チームの方針

  • インフラはNginxとUnicornとMySQLのチューニングを行うのみにして、コード改修に時間をかける。
    (SQL、インデックス、ロジックの見直しをきちんと行えばスコアは上がるという考えです)
  • 各種設定ファイルは事前に準備しておく

 

当日の作業分担

@itoKami1123さんにはアプリ改修に専念してもらい、
僕はサーバの初期セットアップとインフラを担当。後からアプリ改修作業に合流という流れ。
作業しやすいようにサーバは1人1台ずつ立てて、僕のサーバに2人の変更をマージしていきました。

 

当日の作業内容まとめ

  • MySQLチューニング (my.cnfは事前に準備しておいた)
  • Nginxチューニング (nginx.confは事前に準備しておいた)
  • ログイン時のユーザがロックされているかのチェックでlogin_logを見なくて良いようにするために、usersテーブルに列追加
    エラーカウンタ列(ログインエラー時にインクリメント、ログイン成功時に0をセット)
    成功カウンタ列(ログイン成功時にインクリメント)
  • mypageに表示する最終ログイン情報(前回ログイン日時と最終ログインIPアドレス)もusersテーブルに列を追加して、login_logを見なくて良いようにする
  • 最終ログイン情報はインスタンス変数に保持して、DBは参照しない
  • 禁止IPを記録する専用テーブルを作って、ログイン時のチェックでlogin_logを見なくて良いようにする
  • “SELECT *” をやめる
  • unicornのワーカー数を4にする
  • workloadを5にする

 

当日の時系列な流れ

09:20 昼飯持参で会社集合

  • 会議室にディスプレイを持ち込んで会場設営
  • 当日マニュアルを印刷して内容を確認

10:00 公開されたAMIでサーバ起動

  • ソースコード一式を印刷
  • 画面を動かす
  • 初期ベンチ実行 初期スコア:1279
  • 初期ソースコードをGitで管理
  • 初期設定ファイルをGitで管理

10:20 作戦会議

  • 画面を動かしながらソースの確認
  • 作業内容を決定

12:00 作業開始

13:00 MySQLチューニング完了
スコア 1279 -> 1329
my.cnfは準備済だったけど、それを使うとMySQLが起動エラーになったのでmysql_install_dbで初期化からやり直し。
起動はするようになったけど、ベンチツールの実行でエラーが出てハマる。
max_allowed_packetが小さい事が原因だった。
初期設定ファイルの設定値(300M)にする事で解決。
予定外の大幅な時間ロス・・・(ToT)

13:20 Nginxチューニング完了
スコア 1279 -> 1329 -> 1420

15:30 ユーザがロックされているかの判断をusersテーブルで行うアプリ改修が完了
スコア 1279 -> 1329 -> 1420 -> 2145

15:40 “SELECT *” をやめる
スコア記録取り忘れ・・・(大きな改善は無かった)

15:50 users.loginにインデックスを貼る
スコア記録取り忘れ・・・(大きな改善は無かった)

16:20 前回ログイン日時と最終ログインIPアドレスをusersテーブルに記録するアプリ改修が完了
スコア 1279 -> 1329 -> 1420 -> 2145 -> 2754

16:30 最終ログイン情報をインスタンス変数に保持するアプリ改修が完了
スコア 1279 -> 1329 -> 1420 -> 2145 -> 2754 -> 2850

17:40 unicornのワーカー数とベンチツールのworkload調整完了
スコア 1279 -> 1329 -> 1420 -> 2145 -> 2754 -> 2850 -> 5229
ワーカー数:4 workload:4

17:56 禁止IPを記録する専用テーブルのアプリ改修が完了
スコア 1279 -> 1329 -> 1420 -> 2145 -> 2754 -> 2850 -> 5229 -> 19608
それまでCPUをMySQLが100%食いつぶしていたけど、MySQLのCPU使用率は15%くらいまで下がって、Unicornが次のボトルネックになった

17:59 ベンチツールのworkload調整完了
スコア 1279 -> 1329 -> 1420 -> 2145 -> 2754 -> 2850 -> 5229 -> 19608 -> 20835
workload:4 -> 5

 

タイムアップギリギリの17:59に最高スコアを提出したけど、間に合ったかな・・・?

 

時間内にやれなかった事

  • Sinatraのproductionモード設定を忘れてた・・・。
  • ロックユーザ情報と禁止IP情報はlogin_logを使わずに取得できるようには出来たので、
    もうちょっと時間があれば/reportでjsonを返すロジックを改修して、login_logへのinsertを無くす事が出来たと思う。

 

AMI提出後に試してみた事

  • Sinatraをproductionモードにして、workloadを8にしてみたら36000というスコアが出た。悔やまれる・・・。
[isucon@ip-xxx-xxx-xxx-xxx ~]$ ./benchmarker-v2 bench --workload 8
02:58:37 type:info      message:launch benchmarker
02:58:37 type:warning   message:Result not sent to server because API key is not set
02:58:37 type:info      message:init environment
02:58:46 type:info      message:run benchmark workload: 8
02:59:46 type:info      message:finish benchmark workload: 8
02:59:51 type:info      message:check banned ips and locked users report
03:00:29 type:report    count:banned ips        value:540
03:00:29 type:report    count:locked users      value:4187
03:00:29 type:info      message:Result not sent to server because API key is not set
03:00:29 type:score     success:167350  fail:0  score:36151

 

最後に

仕事では基幹業務システムを作っていて、言語はJava、DBはPostgreSQLという僕達2人でしたが、とても楽しかったです。
本線に出場できるようなスコアは残せませんでしたが、きちんと準備して臨んだおかげで大きなミスや、もたつきもなく作業でき、
failせず終われたので個人的には結構満足しています。

一緒に出場してくれた@itoKami1123さん、運営の皆様ありがとうございました!!