ISUCON13 参加記 (最終スコア: 0点, 最高スコア: 37,364点)
ISUCON13にチーム名「うどんきれいなGo」参加し、惜しくも優勝を逃しました。
次回に向けて、備忘録を記します。
内容は参加した人向けになっています。
メンバー
ISUCON8から毎年同じメンバーで参加しています。
takutaka1220: インフラが得意、主にインフラ担当
iceman5499: iOS が得意、主にアプリケーション担当
yush1ga (私) : 機械学習/データエンジニアリングが得意、主にアプリケーション担当
練習
毎年1日使ってチームで集まって前回のISUCONの問題を解いています。
問題の環境構築は年々簡単になっている印象で、今回はISUNARABEというサービスを使わせて頂くことで簡単に構築できました。
個人では、Goのリハビリをチョットだけやりました。
当日
当日の動きはおおよそこんな感じでした。
ER図を描く
例年なら絶対やらないですが、今年はChatGPTを使って一瞬で作れたのでER図を作りました。
プロンプトは以下のような感じ。
(前略)
mysql> DESC users;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | UNI | NULL | |
| display_name | varchar(255) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| description | text | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
ER図を PlantUML で書いてください
外部キーについては推論してください
怪しいところはあるものの、データ構造の把握には役立ちました。
slow_query_log を on にする
お約束ではありますが、スロークエリのログをオンにしました。
[mysqld]
slow_query_log = 1
long_query_time = 0.5
log_output = TABLE
私はスロークエリはファイルではなく、テーブルに吐き出すのが好きです。
SELECT
start_time,
query_time,
db,
LEFT(CONVERT(sql_text USING utf8), 256) AS sql_text_short
FROM
mysql.slow_log
WHERE
start_time >= ${ベンチ回した時間} AND
CHAR_LENGTH(CONVERT(sql_text USING utf8)) <= 4000
ORDER BY
query_time DESC;
のようなクエリを書くことで、特定のベンチマークに絞ったスロークエリを実行時間の長い順に抽出することができます。
kataribe の結果を眺める
我々のチームでは、`make kataribe` とコマンドを叩くと nginx のログを kataribe で解析した結果が Slack に投稿されるようにしています。
アクセスの多いリクエストや平均処理時間の遅いリクエスト、トータルの処理時間が遅いリクエストなどを確認することができます。
結果の確認と修正のサイクルの繰り返し
kataribe の結果とスロークエリログを見て、インデックスを貼ったり、アプリケーションの該当箇所を修正するというサイクルを繰り返しました。
近年のISUCONはインデックスを貼ろうと思ったら既に貼ってあったり、N+1が案外見つからなかったりすることも多い印象でしたが、今回はわりと色々見つかり、やることには困りませんでした。
修正することで着実にスロークエリログは減り、kataribe の結果も顔ぶれも変わっていきました。
この間インフラ側では水責め対策のあれこれ等をやってくれていました。
(詳しく把握していない。)
スコアも初期の3546点から、12852点まで伸びました。
サーバーリソースの分散
やることに困っていなかったこともあって、サーバーリソースの分散に取り組むのがかなり遅れました。
16:30頃になってもアプリケーション側でやれることはたくさんありそうでしたが、時間もないしCPUは100%に張り付いてるしスコアは伸び悩んでるしそろそろサーバーリソースの分散に取り組んだ方がいいという話になりました。
アプリケーション・DNSサーバー + アプリケーションDBに分離
アプリケーションサーバー + DNSサーバー + アプリケーションDB に分離
という二段階でやりました。
1の時点で18437点、2で36466点まで伸びました。
この辺はtakutaka1220にメインで動いてもらっていて、私は雑用的にベン
チポチしたり、サーバーをリブートしたり、ベンチ中のCPUやメモリの利用を監視したりしました。
また、途中DBのメモリが全然使われて無いことに気付いたので innodb_buffer_pool_size を増やしたり、 最終ベンチに向けて slow_query_log をオフにしたりしました。
3台構成にしたあと、nginx でエンドポイントごとにロードバランスでさらなるスコアアップを狙いましたが、上手くいかなかったので切り上げることになりました。
ここまでで、37364点。
破壊
17:45 辺りで作業を切り上げて再起動試験に備えてサーバーを全台リブートしました。
そして、PowerDNSによる名前解決ができなくなりました。0点。
2023-11-25T08:45:25.828Z info isupipe-benchmarker SSL接続が有効になっています
2023-11-25T08:45:25.828Z info isupipe-benchmarker 静的ファイルチェックを行います
2023-11-25T08:45:25.828Z info isupipe-benchmarker 静的ファイルチェックが完了しました
2023-11-25T08:45:25.828Z info isupipe-benchmarker webappの初期化を行います
2023-11-25T08:45:37.058Z info isupipe-benchmarker ベンチマーク走行前のデータ整合性チェックを行います
整合性チェックに失敗しました
Post "https://jGNJiMsMcy.u.isucon.dev:443/api/livestream/reservation": 「jGNJiMsMcy.u.isucon.dev」の名前解決に失敗しました (rcode=3): ベンチマーク走行が継続できないエラーが発生しました
反省
筋力が足りない
2021年頃までは仕事でGoのバックエンドを書く機会が多少ありましたが、それ以降はバックエンドの開発する機会もあまりなく、Goもほぼ年一しか書かないので、年々衰えを感じています。
目についた問題を素早く解決する筋力がなくしょーもない部分でもたついてしまいました。
よりクリティカルな部分を見つける嗅覚を養うという手もある気がしますが、実装力を高めてすぐ書けるようにする方が再現性がありそうなので、こちらで行きたいと思います。
Go 自体は好きな言語ではあるので、ISUCONの時期だけでもなんとかしたいです。
サーバーリソースの分散に取り組むのが遅い
今更の反省ではあるのですが、我々はそれほどたくさん練習時間を取れているチームではないので、壊しやすいサーバーの分散作業には早めに取り組んだ方が良いと思いました。
今まで運良く再起動で fail したことは無かったのでなめていたところがあります。
次回はあらかじめ時間決めてやりたいと思っています。