ISUCON10に参加してきた
ISUCON10予選に参加してきました。予選は例年リモート開催のため参加者としてはあまり昨今の情勢下で変わった事はありませんでしたが、運営チームは準備から当日まで大変だったのではないかと思います。運営の方々に感謝します。
3人チームで参加。選択した言語はRuby。再起動試験でFailしたらしく最終スコアは0でした。最高スコア970ぐらいで止まっていたと思います。
事前準備
私は最近の仕事がTypeScriptかPythonばかりでRubyはあまり書いていない(そもそもWebをあまりやっていない)ので、リハビリがてらSinatraの練習をしていました。練習していた内容をだいたい記事に起こしたものが下記Qiitaになります。Ruby、久々に書いてみると良い言語ですね。
ISUCONは最初の1時間で何をするかが大切、ということで、私は例年開発環境構築担当なので、上記のようなダミーアプリの開発やISUCON過去問を含めて5,6回、開発環境構築を素振りしておきました。
あとは過去問のレギュレーションに沿った模擬戦や、過去できなかったポイントの復習、当日の流れの確認などをしていました。前日に競技開始時間を間違えているメンバーがいたので、ちゃんと集合時刻など当たり前のことも含めて確認することが大切です。
なお私は、特にアプリケーションのボトルネックを打破する武器としてRubyからRustを呼び出す練習をしていたのですが、今回それを使うところまで至らなかったのは大変悔しいです。
▲悔しさの残るコミットログ
最初の1時間
競技開始直後はトラブルがあってベンチマークが回せませんでしたが、事前の打ち合わせ通りに開発環境構築、マニュアルの確認、必要なツール類のインストール等をチームで手分けして行いました。
私は開発環境構築を担当。ソースコードをscpで取ってきてライブラリインストール等のコマンドを組み合わせてローカル環境で動作させて配布する所までです。isuumo/webapp/ruby ディレクトリまでで切るか、isuumo/webapp まで含めてgit管理するかが好みの分かれる所だと思います。私は isuumo/webapp/ruby にしていたのですが、後から isuumo/webapp/sql を別途git管理することになりました。このあたりは事前にもっと突き詰められたと思います。
環境構築に必要なコマンドはリポジトリのREADME.mdに書いた後、自作のRust製ツールi-readからコマンド実行して構築・確認していきました。たとえば今回の問題はWebアプリが置いてある isuumo/webapp/ruby にはAPIしか無く、フロントエンドは /www/data に置いてありました(恐らくNext.js製)。
$ scp -r (ISUCON10予選サーバ):/www/data/ ./public/
フロントエンドは容量が膨大でありISUCONにおいては変更することも無いためgit管理には含めず、このようなコマンドでローカルにコピーしてから開発環境として使っていました。こういったコマンドをREADME.mdに書いてからi-readで実行していくと、コスト無しで最低限のドキュメントが完成し、自分自身もチームメンバーに共有する時も楽です。シェルスクリプト等とお好みですが、普段の業務の延長線上として、私はいつもこの方法で開発しています。
私のPCにはRubyもMySQLも入っておらず全部Dockerで済ましているため、開発環境もすべてDockerで動作するようにしてメンバーに配布しました。開発環境の構築の容易さ・再現性の高さという意味ではDockerで構築するのが良いと思います。ただ、私はLinuxデスクトップ環境を利用しているのですがチームメンバーはMacであり、Dockerのパフォーマンスや安定性に大きな差がありました。メンバーと相談は必要です。
競技開始が12時20分、開発環境構築のコミットが12時57分だったので、約30分。ここまでは悪くないペースだったと思います。
残りの7時間
私の担当した中でおもなタスクは下記のような感じでした。
・開発環境構築および修正
・NewRelic導入
・DB LIKE検索クエリの別テーブル化
・Web+App×2台構成化
・DB Writer+Reader×2台構成化
・DBインデックス調整
dstat、alp、MySQLスロークエリログなど各種メトリクスを導入していましたが、計測結果を十分に確認せず推測で進めていた施策が多かったというのが最大の反省です。チームがそういう状況になった要因は明確なのですが、言い訳は無駄なのでしません。己の未熟さが故です。
上記の例で言えば「App×2台構成化」が該当するのですが、今回の問題の初期状態はアプリケーションの負荷がさほどでもなく、いきなりAppを負荷分散しても全くと言っていいほどスコアが上がりませんでした。
その後、DBにレプリケーションを貼って3台構成にしてReadクエリを2台に分散したところ、結構スコアが伸びたので喜んでいました。しかし一方でエラー数も大きく増えていました。これは恐らくI/Oの性能が厳しい環境下でレプリケーション遅延が発生しており、購入したい商品が購入できないといったエラーが増加したためだと思われます。こちらも計測していれば悪手だと気付いたと思います。
なお競技中はMySQLのレプリケーションの貼り方も忘れていたのですが、過去に自分が書いた記事が大きな助けになりました。継続的なアウトプットが大切なのは変わらず。
以上、ひとことで言えば「推測するな、計測せよ」に尽きたと思います。お疲れさまでした。