COLOPL Tech Blog

コロプラのエンジニアブログです

ISUCON12予選に参加しました

こんにちは。2019年新卒サーバーサイドエンジニアの薮です。

7/23 (土) に開催された ISUCON12 予選 1に同期とチーム「無限にカレーを食べる会」で参加しました!

参加メンバー

  • taro
    • 同じく2019年新卒同期のサーバーサイドエンジニア
    • 今回が ISUCON 初参加
    • 本投稿の執筆者
    • ISUCON7予選、ISUCON8予選に参加経験あり

最終スコアは 9284、105/698 位で残念ながら予選通過ならずでした!

問題の詳細な解説は公式ブログ 2 が大変分かりやすいため、この記事では練習から本番までのざっくりとした流れと感想をご紹介します!

練習期間

taro はISUCON初参加だったため、まず ISUCON11 予選を自力や解説を見ながら解いて雰囲気をつかんでから、本番を想定して ISUCON10 予選を解いてみる形式で練習を行いました。

なお、練習環境の構築にはAWS上にISUCON用のインスタンスを立てる便利な terraform が公開 3 されていたため、こちらを利用させていただきました 4 。 毎週水曜終業後に結構ガッツリ時間を取ってAWSインスタンスを立てましたが、月1000円も行かず意外とお手軽に勉強できました。

ISUCON12予選

事前準備

練習期間の経験を踏まえ、下記の準備を用意しておいたおかげで本番はスムーズにセットアップできました。

1. 各種サービスのリスタートなどの便利コマンドを定義した Makefile の雛形を作成

例えば今回は下記の Makefile を作成しました。これによって各種検証や他のサーバーへの変更反映がスムーズに行えました 5

fetch:
    git fetch -p
    git reset --hard origin/master
    git clean -df
    cp conf/.gitconfig ~

deploy-app1:
    sudo cp conf/nginx/nginx.conf /etc/nginx/nginx.conf
    sudo cp conf/nginx/sites-enabled/* /etc/nginx/sites-enabled
    sudo cp conf/mysql.conf.d/* /etc/mysql/mysql.conf.d/
    $(MAKE) restart-nginx restart-app restart-db
    $(MAKE) clean-log

deploy-app2: deploy-app1

deploy-app3: deploy-app1

restart: restart-db restart-nginx

restart-app:
    sudo systemctl restart isuports

restart-db:
    sudo systemctl restart mysql

restart-nginx:
    sudo systemctl restart nginx

clean-log:
    sudo truncate -s 0 /var/log/nginx/access.log /var/log/nginx/error.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log

install-alp:
    cd /tmp
    wget https://github.com/tkuchiki/alp/releases/download/v1.0.8/alp_linux_amd64.zip
    unzip alp_linux_amd64.zip
    sudo mv ./alp /usr/local/bin
    rm alp_linux_amd64.zip

install-percona-toolkit:
    sudo apt install percona-toolkit

publish-mysql-host:
    mysql -uisucon -pisucon mysql -e"RENAME USER 'isucon'@'localhost' to 'isucon'@'%';"

alp-log:
    sudo cat /var/log/nginx/access.log | alp ltsv -m "/api/player/player/[0-9-a-z]+,/api/organizer/competition/[0-9a-z]+/score,/api/player/competition/[0-9a-z]+/ranking,/api/organizer/player/[0-9a-z]+/disqualified,/api/organizer/competition/[0-9a-z]+/finish" -r

slow-query:
    sudo pt-query-digest /var/log/mysql/mysql-slow.log

ssh-mysql:
    mysql -uisucon -pisucon isuports

2. 序盤に行う環境整備の手順書を gist に作成

本番は焦って手順をど忘れすることを懸念し、下記のような手順書を作成しました。

  • git リポジトリ作成
  • Makefile コマンド整備
  • 残りの app で git から取得できるように整備
  • 当日マニュアル読む
  • 初期データのダンプSQLが .gitignore に追加されてたら外す
  • nginx、MySQL の設定ファイルを git 管理下に追加
  • alp、percona-tool-kit インストール
  • MySQL のスロークエリを有効化
  • nginx のアクセスログを LTSV 形式に変更 (alp 分析用)

午前中

手順書通りに粛々と環境整備しました。

過去問では経験がなかったのですが MySQL の初期データのファイルサイズが大きすぎるトラブルに遭遇しました。 後々のテーブルスキーマ変更やオペミスによるデータ復旧を考慮すると、初期化用のSQLデータも git で管理しておきたく、急遽 Git LFS 6 を導入しました。

お昼

環境整備が整ったのでベンチマークを実行しました。

ベンチマーク実行中に top を見ると特にDBの負荷がボトルネックになっていることに気づき、alp によるレスポンス計測や pt-query-digest によるスロークエリ分析を行いました。

ひとまずすぐ直せそうな簡単なインデックス貼り忘れや N+1 クエリをサクッと直しました。

ここまでは順調だったのですが、アプリの実装を読んでる中で SQLite の使用に気づき、 MySQL に載せ替えるか悩んだところから苦しみ出します。

SQLite の分析方法が分からないこと、後半で複数台構成に切り替える際に SQLite がネックになり得ることから MySQL への載せ替えを判断します。

ここで taro と相談の上、役割分担を行いました。

  • 私 → SQLite から MySQL への載せ替え担当
  • taro → その他のチューニング

ここから SQLite のデータを MySQL に載せ替えを行ったのですが、単純な SQLite のダンプだと遅すぎること、また例えそっくりそのままレコードを MySQL に載せ替えられたとしても、ベンチマーク時の初期化の制限時間に間に合わなそうという予感がしたので、Go で SQLite の必要なレコードのみを取捨選択し MySQL に移行するスクリプトを書きました。

同時に2つのことを行うことにより案の定バグを生み出してしまい、移行スクリプトによるベンチマークがなかなか通らず辛い時間でした。

私は MySQL 移行作業にかかりきりになってしまったのですが、その間 taro がいつの間にかID生成が重い問題を自力で見つけて UUID に移行対応する改善を行い、スコアが 5000 くらい上がって初参加とは思えない大活躍をしてくれました。

17:00〜

競技終了1時間前にして、やっとMySQL移行 + テーブル圧縮スクリプト 7 によるベンチマークが通りました。アドレナリンがドバドバ出たのは言うまでもありません。これがISUCONの醍醐味ですね。 ここからラストスパートで3台を nginx + app、app、DB の複数台構成への移行を行い、最後に滑り込みで諸々のログを切ってベンチマークを回して終了でした。

結果は最終スコア 9284で 105/698 位で予選通過ならずでした。

複数台構成にできたのは良かったのですが、肝心のファイルロックによるトランザクション問題に気づかず手をつけていなかったため、台数分散による恩恵があまり受けられなかったのが悔やまれます…。

感想とまとめ

taro

  • 環境構築が大変そうという先入観を持っていたが、意外に簡単に練習環境を構築できるなどサポートが手厚くて助かった
  • ISUCON初参加と言うのもあり、知識不足で自走できなさそうとビビっていたがスコア向上に貢献できて楽しかった
  • 実際の業務ではそこまで負荷計測 → ボトルネック確認 → 修正 → スループットの向上という流れを経験する機会が少なかったので、流れを体験できたのは良かった
  • 普段インフラ周りは主にインフラチームが担当しているため、ミドルウェア周りの引き出しが増え勉強になった

  • MySQLの載せ替えができたのはかなり嬉しかったが、移行時のバグにハマり3時間くらい時間を潰してしまったのが悔しかった
  • 例年よくあるつまずきポイントに対する勘所が鍛えられたので成長を感じられた
  • 以前より Go 力が上がりサクサクコードを修正できるようになってきて成長を感じた
  • 初参加の taro が ISUCON 参加を楽しんでくれ、また社内のエンジニアLT会で発表してくれたのが素直に嬉しかった
  • taro のLT会発表により社内でも興味を持ってくださる方が増え、社内 Slack の #tech-isucon チャンネルに参加してくださる方が増えて嬉しかった
  • 今後もISUCONの勉強会を社内でも開いて盛り上げていきたい
  • 来年は社内で複数チーム作って出られると嬉しい

今回の予選も総じて解きがいのある問題で大変勉強になりました。 このような素晴らしい競技に参加する機会を提供いただいた運営の皆様に感謝いたしております。

予選のベンチマーカーおよび予選で使われたAMIが公開されたので、今後感想戦を行ってより今後のISUCON予選突破へ近づけるよう精進していきたいと思います!


  1. https://isucon.net/archives/56571716.html
  2. https://isucon.net/archives/56850281.html
  3. https://github.com/momotaro98/isucon-aws-terraform
  4. 余談ですが Apple Silicon Mac 上だと指定している AWS provider のバージョンが未対応により $ terraform apply が失敗したので、修正PR https://github.com/momotaro98/isucon-aws-terraform/pull/3 を作成して取り込んでもらいました。
  5. 省いてしまいましたが、タスクである場合は .PHONY を指定するのが適切です。
  6. https://git-lfs.github.com
  7. 参考までに公開しておきます。https://github.com/tyabu12/isucon12-qualifier/blob/master/go/cmd/sqlite2mysql/main.go