ISUCON14参加記

# はじめに

本記事は[Progaku Advent Calendar 2024 10日目エントリー](https://qiita.com/advent-calendar/2024/progaku) 兼 [ISUCON14 関連エントリ](https://isucon.net/archives/58835757.html)です。

プログラミング学習コミュニティProgakuのメンバーとチームを組んで、ISUCON 14に参加しました。
ISUCONには私含めてメンバー全員が初参加で、Goで参加しました。
一緒に参加してくれたメンバーは、 @inakuuun と @rgj0830 です

結果は[ISUCON14 受賞チームおよび全チームスコア](https://isucon.net/archives/58837992.html)にて秘密のスクリプトともに順位を確認したところ、8033点で176位でした。
合計何チーム出場したのか細かい数字はわかりませんが、800チーム以上はいたはずなので、上位25%くらいですかね。私の中ではかなりの大健闘の成果でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299962/52cca291-af37-2a22-b9d2-f6c7edca1581.png)

<details>
<summary>秘密のスクリプト</summary>

textContentで無理やり突っ込んでいるため、一番下がぐちゃぐちゃになります。

```ts
Array.from(document.querySelector('.article-body-more').children).filter((elm) => elm.constructor === HTMLDivElement).forEach((elm, idx) => elm.textContent = `${idx+1}: ${elm.textContent}`);
```

</details>

スコアの推移は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299962/2ad59b68-c28d-ee40-5382-ec537eeac6b3.png)

17時前に私が頭をバグらせながら直したクエリで0点を出しています。
そのあとすぐに戻して、他メンバーの改善を適用。最後にログを止めて最終スコアとしました。

# 他メンバーの記事

https://qiita.com/rgj0830/items/e3a5e949166d40fb4c20#_reference-dd8375ca04a87fe437e6

https://qiita.com/inakuuun/items/f911c11b8799e74bd5c7

# 事前にやったこと

私がやったことは下記の通りです。

- [ISUCON本](https://gihyo.jp/book/2022/978-4-297-12846-3)を読む
- [private-isu](https://github.com/catatsuy/private-isu)を数回軽くこする
- [nginx実践入門](https://gihyo.jp/book/2016/978-4-7741-7866-0)を読む
- DBサーバー分割の練習
- Git管理練習
- pproteinの導入練習
- ISUCON13の過去問を軽く解く
- ISUCON13の参加エントリーを読み漁る

上記を行うにあたり、下記記事を大変参考にさせていただきました。

https://isucon-workshop.trap.show/

https://qiita.com/rgj0830/items/820ecc61f96e0f11f618

https://zenn.dev/team_soda/articles/20231206000000

https://engineering.nifty.co.jp/blog/23409

https://tex2e.github.io/blog/linux/systemctl-list-services

https://qiita.com/gogonosmarty/items/140526ac7bb4ba956877

https://linuxcommand.net/journalctl/

https://isucon.net/archives/57991509.html

また、private-isuの環境構築で詰まったポイントは下記にまとめました。

https://qiita.com/masayasviel/items/353024f7f2e292572942

そして個人で練習している途中で私の書いた上記事が役に立っていることを発見して嬉しくなりました。

https://zenn.dev/kotap15/scraps/e8b12865b0efcf

[ISUCON13の参加エントリー](https://isucon.net/archives/57991509.html)を読み漁っていたことが、本格的に素振りを始めてからかなり効いていたことがわかりました。

## 前日

役割と当日discordに集まる時間、事前に公開されていたレギュレーションの確認をしました。
GitHubにプライベートリポジトリの作成も前日に行いました。

# やったこと

## 起床

難関ポイント。
9時に起床という偉業を達成し、起きれましたと報告。
ポイントは早めにPCを閉じてスマホを置いて、布団に入ること。
また、久しぶりにちゃんと朝ごはんを食べました。

## 初動

マニュアルは読もうねと昨年の複数エントリで言及されていたのでちゃんと読みました。

https://github.com/isucon/isucon14

- 椅子がライドとマッチした位置から乗車位置までの移動距離の合計 * 0.1
- 椅子の乗車位置から目的地までの移動距離の合計
- ライド完了数 * 5

の通り、点数の付け方が「椅子の移動距離」と「どれだけ人を送り届けたか」なのですが、「マニュアルを読んだだけじゃスコアの付け方分かんねくね？」みたいな話をしてほぼアプリ側を触ることなく終了しました。
アプリのシナリオを通した改善がもろに響くことを知らずに────

マニュアルを一通り読んでメンバーと意見交換をした後はCFnでアプリを立ち上げ、初回ベンチをまわしました。
このとき971点。

gitの設定とDBサーバーの分割をはじめ、12時過ぎに完了。1235点と若干伸びました。
分割完了後、分割先のDBサーバーに各々のDBクライアントで接続を行いました。
私はDataGripを使っていたので初期状態のER図を吐き出しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299962/e4b6336e-266a-cfa2-fab8-999d5ccf2b8c.png)

ここで一区切りついたし12時も回っているからということで一旦お昼を取ることにしました。

## 中盤

お昼から戻ってからpproteinの導入。
過去エントリでSGを変えたら失格という記載を見かけていたので、もしそうなら導入できないねと話をしていたのですが、変更OKでした。

https://github.com/isucon/isucon14/blob/main/docs/manual.md#%E7%AB%B6%E6%8A%80%E7%92%B0%E5%A2%83%E3%81%AE%E5%A4%89%E6%9B%B4

練習していたので沼ることなくpproteinの導入完了。

アプリのinitializeを見ると、いつもの通りinit.shが呼ばれており、init.shを見るとMySQLのテーブルが作りなおされていたので、private-isuのように直接DBに入ってインデックスを貼るのではなく、webapp/配下のSQLファイルに追記していくのだと気づけました。
この辺は素振りが活きていました。

今回はenv.shを変更するだけで良かったし、env.shについてアプリケーションマニュアルで言及されていたので必要なかったのですが、なぜenv.shを書き換えると環境変数が変わるのかについても把握していたので、systemctlで呼び出される `/etc/systemd/system/` も確認しました。

そこからはチームメンバーにslowqueryをみながらインデックスを貼ってもらったり、不要なトランザクションを削除してもらったりしていました。
私はその間、nginxの設定とアプリ側の改修をしていました。

nginxは静的ファイルのキャッシュのみできました。弱すぎる。
下記が対応した内容の一部抜粋になります。
せめてかっこよく正規表現でまとめられたら良かったのですが、できなかったので泥臭く書きました。弱すぎる。

```diff
server {
  root /home/isucon/webapp/public/;
  location / {
    try_files $uri /index.html;
  }
+   # PNGファイル
+   location ~* \.png$ {
+    expires 8h;
+     open_file_cache max=1000 inactive=60s;
+   }
+
+   # assetsディレクトリ
+   location /assets/ {
+     expires 8h;
+     open_file_cache max=1000 inactive=60s;
+   }
+
+   # imagesディレクトリ
+   location /images/ {
+     expires 8h;
+     open_file_cache max=1000 inactive=60s;
+   }
+
+   # favicon.ico
+   location = /favicon.ico {
+     expires 8h;
+     open_file_cache max=1000 inactive=60s;
+   }
}
```

アプリ側はN+1の解消すらできず、ループ内で呼ばれているクエリの一部を一つにまとめるくらいしかできませんでした。
叩かれるクエリが減っただけでN+1は解消できていないので、これで100点ほど上昇。
「はじめに」に記載の通り、そのあと取り組んでいた改善は適用したところ0点になったのと時間が終了1時間前の17時だったこともあり諦め。

私が詰まっていたのは各ライドごとの最新の状態を取得する部分で、row_numberとoverを用いた最新値の取得をするクエリに変更していたのですがうまくいかず。

https://qiita.com/katao_eng/items/62ce979108b302fc3f1e

終了後に、「そもそもテーブル構造を変えて、各ライドごとに1つしか状態が紐づかないように変える」と解説がありました。また、通知に対するリクエストが多かったのですが、これもインターバルをさらに空けることで点数が伸びたと総合優勝したtakonomuraさんがインタビューで話していました。
アプリ側を触っていれば、マニュアルの記述と結びついて、もしかしたら偶然でも気づけたかもしれないのに。
基本裏側のパフォーマンスチューニングなので、バックエンドに視野が狭まりましたが、"アプリケーション全体"に対して目を向ける気づきを得られました。

## 終盤

17時30分にはログを閉じてベンチを回すと事前に決めていたので、その通りに対応しました。
ログを閉じる前の最終スコアは6595点でした。

念のため追試環境の確認もしておこうと、

https://github.com/isucon/isucon14/blob/main/docs/manual.md#%E7%AB%B6%E6%8A%80%E7%92%B0%E5%A2%83%E3%81%AE%E7%A2%BA%E8%AA%8D

にあるとおり `sudo /opt/isucon-env-checker/envcheck` を叩いたところ、pprotein用に立てたサーバーがfail対象でした。
確認しておいてよかった......！
pproteinも消して追試環境確認も通ったので、最後にログを消したものでベンチを回します。
成功して、その日最高得点の8033点を出しました。

もうこれ以上回さず待とう。
雑談しながら終了を待ちました。

# おわりに

楽しかったし、チームとしては大健闘でした。
一緒にチームを組んでくれた2人がめちゃくちゃ練習をしてくれていて、何とかいい結果に結び付いてほしいと思っていたので叶ってよかったです。

ただ私個人としては素振り不足知識不足を実感しました。
メンバー2人が点数を上げている間やっていたことは点数微増のアプリ開発だけです。nginxはスコアアップに寄与しているのかすらわかりません。
また、総じて言えるのが生成AIを使うのが下手すぎるということです。
全然使いこなせませんでした。この辺も素振りのとき使えば良かったです。
自信を持って言えるのは、練習段階でDB分割とpproteinの手法をチームに持ち込めたことくらいです。

反省はありますが、それでもマイルストーンを達成したときの高揚、スコアが一気に上昇したときの快感、ISUCONのお祭り感。いずれもまた得たくなるものでした。また、本番までのメンバーと一緒に素振りしたり輪読会したりするのも楽しかったです。
総じてまた来年も参加したいと思えるものでした。

次回も参加出来たら(チキチキISUCON参加権取得早押し大会に勝つ必要がある)、今回得られた知見と反省でさらなるパワーアップをして臨みたいです！

以上、[Progaku Advent Calendar 2024 10日目エントリー](https://qiita.com/advent-calendar/2024/progaku) 兼 [ISUCON14 関連エントリ](https://isucon.net/archives/58835757.html)でした！

おわりだよー(o・∇・o)