ISUCON12予選に出場しました!(チーム:わいわいわい)
こんにちは。ニフティライフスタイルでスマホアプリの開発をしているsaikeiです。
2022年7月に開催されたISUCON12の予選に社内チームで初参加してきたので参加記録を残しつつ、今回の流れを振り返っていきたいと思います。
目次
ISUCONとは
ISUCONとは Iikanjini Speed Up Contest(いい感じにスピードアップコンテスト) の略で、お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトルです。
参加目的
ISUCONに参加するための事前準備や本番を通じてメンバーの知識・技術力の向上と組織の活性化を目的に、今年初めてニフティライフスタイル社として2チーム(各3人)の出場を行いました。
参加メンバーに関しても技術領域を問わずに募り、私のように普段iOSアプリ開発を行なっているメンバーから、インフラのスペシャリストまで多種多様なメンバーが参加しました。
参加メンバー(チーム:わいわいわい)
- nakanowai
- 新卒入社10年目
- 業務ではサーバサイドの開発運用とAWSマルチアカウント管理を担当
- ISUCON9以来の2回目の参加
- saikei
- 新卒入社4年目
- 業務では主にスマホアプリの開発を担当
- ISUCONはもちろん初参加
- SoraY677
- 中途入社7ヶ月
- 業務ではWebのフロントエンドをメインで担当
- ISUCONの存在は知っていたが、参加するのは初
予選当日まで(事前準備)
今回参加したメンバーのほぼ全員がISUCON初参戦という事で、全員で過去問(ISUCON11予選)を解く会を2日設けました。
当日の立ち振る舞いを体験するために、実際にレギュレーションやマニュアルを読む所から改善を実施するという流れで実施したのですが、事前に調べておいた方が良い事(各種設定方法)や、用意しておいた方が良い物(デプロイスクリプト等)も把握する事ができました。
この会が無ければ予選当日に何から手をつけて良いのかわからずバタバタしまっていたと思うので、結果的に非常に良い準備だったと思います。
予選当日
普段の業務はほとんどリモートで実施しているのですが、当日はコミュニケーションの取りやすさも踏まえメンバーの全員の希望で社内の会議室を借り、感染症対策に気を配りながら対面で参加しました。
使用言語は3人で共通した得意言語がなかったため、あえて誰も使ったことのないGo言語を選択しました。
また、ドキュメント管理はConfluence、コミュニケーションツールはSlackと普段業務で使い慣れているシステムを使用する事で、学習コストを抑えつつ情報の共有を行いました。(いずれも競技中はチーム外閲覧制限を設定)
タイムラインとしては最初の1時間で環境構築をしつつ全員でドキュメントを確認し、その後各々作業を行いました。
また、失格を避けるために競技終了1時間前に再起動試験を実施し、15分前にはコードフリーズを実施しました。
改善項目
実際にわいわいわいが実施した改善項目は以下の通りです(抜粋)
- アプリケーションとMySQLのサーバー分離
- SQLiteをメモリに載せる
- 各種ログの出力(&最終的な停止)
- 不要サービスの停止
- DB(MySQL)にINDEXを貼る
- …
この中からいくつか紹介させていただきます。
デプロイスクリプトの用意
今回デプロイを手動で行う場合の一例として
- ローカルからリモートリポジトリ(GitHub)にコードをコミットする
- 全3台の競技サーバ上で対象のディレクトリに移動
- リモートリポジトリ(GitHub)から最新のコードを取得
- 各種アプリケーションを再起動
- 競技ポータルサイト上からベンチマークを実行
という手順が考えられました。
特に2〜4に関しては、競技サーバ上で複数のコマンドを順番に実行する必要があるため、僅かではありますが毎回工数がかかってしまいます。また、順番やコマンドを間違えてしまうと意図せぬ変更となりサービスが動かなくなってしまう事も想定されました。
このように、ローカルで改善したコードをいかにスムーズにストレスなく本番環境に反映できるかという点が、チーム開発を効率化する上で大切なことだと事前準備(過去問題)を通して学ぶことが出来ました。
そこで私たちはデプロイを補助するためのデプロイスクリプトを事前に用意しておくことにしました。
デプロイスクプトの内容的は数行程度ではありますが、結果的にはデプロイ時のコマンド量が大幅に減ったため開発スピードの向上に繋がりました。
計測ツールの導入
私たちのチームでは計測のために定番のalpを導入しました。
これはnginxのアクセスログを解析し、わかりやすく可視化してくれるものです。
特にISUCONでは、場当たり的に改善していくよりも「計測・解析」をして改善点にアタリをつけるということが大事だと言われていたため、計測ツールは競技が始まって真っ先に導入しました。
結果として、ボトルネックにすぐ気づくことができ改善箇所の発見をスムーズに行うことができました。
また、Go言語をほとんど知らないチームではありましたが、その場で解読出来る程度の余裕が生まれ、コードの修正で点数を上げるというところまで辿り着くことができました!
アプリケーションとDB(MySQL)のサーバー分割
初期状態ではWebアプリケーションとDB(MySQL / SQLite)が1台のサーバー上で実行されていました。
事前準備で行った過去問(ISUCON11予選)ではMySQLを別サーバーに移動してリソースを有効活用することでスコアを伸ばすことができたため、同じ要領でサーバー分割を行いました。
具体的には docker-compose-go.yml#L5 で指定している環境変数 ISUCON_DB_HOST
を2台目のサーバーのホスト名に変更しました。
- ISUCON_DB_HOST: 127.0.0.1
+ ISUCON_DB_HOST: isuports-2.t.isucon.dev
この変更により、初期状態から400点程度スコアが上昇しました。
DB(SQLite)のオンメモリ化
SQLiteについては基本的にリモート接続させることはできないため、IO性能の向上を期待してDBファイルをtmpfsに配置するように変更しました。
具体的には docker-compose-go.yml#L12 で指定しているボリュームマウントを /dev/shm
に変更しました。
- - /home/isucon/webapp/tenant_db:/home/isucon/webapp/tenant_db
+ - /dev/shm:/home/isucon/webapp/tenant_db
この変更により、700点程度スコアが上昇しました。
バルクインサート化(MySQL)
大会のスコアをCSVでアップロードする箇所が「CSVを1行ずつ処理&INSERT」していた為、バルクインサートに置き換えようとしましたが、修正後にベンチマークを数回回したところポイントが改善するどころか僅かに下がってしまった為、修正を切り戻してしまいました。
しかし競技終了後に他チームの改善を確認したところ修正方法は間違っておらず。正しい改善ポイントである事が発覚した為、ベンチマークのブレを引いて無駄に切り戻してしまっていたという事に気付き後悔しました。
不要サービスの停止
サーバー分割を行なったため、アプリケーションサーバーではMySQL等を、DBサーバーではアプリケーション等の不要サービスを停止しました。
サービスの停止自体では特にスコア上昇することはありませんでしたが、不要であることには間違いなかった為こちらは切り戻さずに実施しました。
※ 得点が数万台になったり、他の改善を実施するとセットで効いてくる改善もあるため「その時点でプラマイゼロ」の改善は基本的に切り戻さずに採用していました。
結果
結果は 4,144点(285位)とあまり振るわなく、ISUCON11の予選問題を解いた時の得点感とはだいぶ離れていたのですが、再起動追試確認を事前に行っていた事で失格になることなく記録を残す事が出来てよかったです。
やって良かった事
- 過去問をチームで取り組む
- 改善できた点や手順をドキュメントにまとめておいた事で当日スムーズに進められた 🎉
- レギュレーションを読み込む&再起動試験(追試)の事前確認
- 失格のリスクを減らせた 🎉
ISUCON12に参加してみて
結果自体は振るわなかったものの、事前準備や本番を通して個々のメンバーが主体的に「自分の今できる事」を行い、当初の目的であるメンバーの知識・技術力の向上が行えました。
個人的には普段スマホアプリの開発業務を中心に行っている事もあり「自分に出来ることはあるのだろうか」と不安に思っていましたが、事前準備を通してある程度学ぶことで実際に得点貢献できて嬉しかったです。
また、サーバーに入る事やWebアプリケーションに触れる機会もあまりなかったためとても新鮮で楽しい時間を過ごせた事はもちろん、「メモリの使い方」や「N+1問題」など普段のスマホアプリ開発にも同様に活かせる経験を積むことができました。
予選後にチームで振り返ると「あの時こうしていればよかった」「これを準備しておけばよかった」などという反省もいくつか出てきたので、来年また開催された暁には今回の経験を活かしてさらなる高得点を目指して参加できたらなと思います!
参加されたみなさま、運営のみなさまおつかれさまでした!
掲載内容は、記事執筆時点の情報をもとにしています。