ISUCON 2026 にチーム「へしこず」で参加して 63 位だった


結構経ってしまったが ISUCON 2026 の参加記録を公開する。
事前準備はほぼなし、前日に ISUCON 14 の問題を AI に解かせて優勝者のスコアを超えるところまで確認して「これどういう戦いになるんだ……?」という感じで挑んだ。
が、終わってみると、「いつもの ISUCON だった」という気持ちと「新しい ISUCON が始まった」という気持ちが入り混じる、とてもいい体験をさせてもらえた大会だった。運営の方々ありがとうございました。

結果としては、どうにか 10 万点を超えて 63 位という結果。全体で見た時は割と上の方ではあったが、弊社の別チームが 7 位となっていて、そこに負けたのがくやしい!
そちらのチームが書いた以下のブログのほうがこのブログよりもしっかり書かれているのでぜひ読んでほしい。
ISUCON2026 参加記(新社屋2 / 最終 7 位・436,993 点)

ここからは、AI にまとめてもらったものに一言付け加える形でまとめたものとなる。以下のアイコンは AI 文章、それ以外は私が手書きしている。

  • 💬 書いたプロンプト
  • 🤖 AI のやったこと
  • ▶️ 他メンバーからの PR

1. 準備(〜10:25)

  • 例年通り webapp 以下を GitHub にすべて投入。
  • 例年と違うのは manual.md にレギュレーションを転載してコミットしたことと、 AGENTS.md を削除したこと。
  • AGENTS.md そのままにしとくと「本番環境だから触らない」とか色々書かれてたので良くないと判断した。
  • 💬「これから isucon を始めます! とりあえず軽く中身見てみてください」

2. 初期チューニング(10:32〜11:26)|6,817 → 約 25,000

  • 💬 /goal「これから 1 時間、ベンチマークの結果がなるべく高くなるように、manual.md と README の中身を確認したうえで、改善を進めてください。コミットするときにスコアの数字をコミットログに入れてください。」
    • とりあえず 1 台だけひたすら改善を回し続けるマシンを用意しとこう、という方針でこうした。3 人でどううまく分担するかがあまり整理できていない段階。
  • 🤖 インデックスの追加、画像署名のキャッシュ、PostgreSQL 設定の調整
  • 🤖 ロック競合を解消し、閲覧者情報・投稿・コメント・RealMoji などで DB への往復を削減
  • 🤖 DB 接続を使い回すようにし、取得処理の一部を並列化
  • 🤖 GC の頻度を下げる設定(GOGC=200)を試したが、効果は小さめ
  • 🤖 画像の寸法超過を、ヘッダーだけで判定するように変更
    • このへんまでは例年通り? 例年ならこれで 4 時間くらい溶かしてる気はするので時代は変わったなぁという感じ
  • 💬 「画像を DB に入れているのはボトルネックの原因になっていないでしょうか?」「europe や america が asia2 の DB を見に行く構成ですが、そもそもこれをなんとかできないでしょうか?」「DB 接続の TLS 無効化、これそんなに効きます?」
    • コミットの内容を読んでて疑問に思ったことを聞いてみてる。なんとなくこのままだと思い切った改善は行われなさそうな気がし始めている段階。

3. DB 関数化と設定のリポジトリ管理(11:36〜12:45)|約 63,000

  • 💬 /goal「これからさらに 1 時間、ベンチマークの結果がなるべく高くなるように改善を進めてください。DB の構成変更、署名の回数を減らすなど、仕様を変えることで大きな改善が見込めるものがあれば、こちらに確認してください。あなたの権限でできないことでもこちらで対応します。」
    • 少しアクロバティックな改善もさせようとしているが、あまりうまくはいってない。
  • 🤖 DB 接続の TLS を無効化し、アップロード画像の検証を軽量化
  • ▶️ nginx 設定と、それを安全に反映する手順をリポジトリで管理
    • 他メンバーもそれぞれ AI 使って PR 投げよう、という話になったのがこのあたり
  • 🤖 セッションの検証結果をアプリ内にキャッシュ
  • 🤖 投稿作成・ログインなどを DB 関数にして、1 往復で済むように変更
  • ▶️ 通知の SSE を、ポーリングから pg_notify で配る形に変更
  • 🤖 画像署名の計算を europe1/america1 に委譲
  • 🤖 通知を DB に保存せず、投稿期間から計算する方式に変更
  • 🤖 nginx の接続上限を引き上げ、PostgreSQL の設定をリポジトリに控えた
  • ▶️ 画像署名の計算回数を削減
  • ▶️ サーバー設定と、検証・復元付きの配置スクリプトを整備
  • 💬「立てたサイトを実際に操作して、どのようなリクエストが飛んでいるか調べてください。怪しいなと思っているのは、X-Country-Code で振り分けるとのことだけど画像などのリクエストにこれがつくのか?というところです。」
    • 一応疑ってみたんだけど他のこと考えてるうちに忘れてた
  • 🤖 2 本の PR を組み合わせたときと単体のときでベンチを取り比べ、マージ

4. クエリの絞り込みと観測の仕組み(12:47〜13:47)|約 72,000

  • ▶️ 投稿 1 件の閲覧可否判定で、友達の友達を全員分展開しないように変更
  • ▶️ アクセスログに X-Country-Code を記録
  • 🤖 docker compose でローカル環境を再現できるように整備
    • AI が確認のためにすぐ SSH したがるので、これをやってローカルで開発が完結できるようにした
  • ▶️ 各フィードを SQL 側で 51 件に絞り込み
  • 🤖 初期化の全件走査をなくし、画像キャッシュを世代方式に変更
  • ▶️ ユーザー検索の絞り込みと、プロフィール取得の 1 クエリ化
  • 💬「(track_io_timing を有効にして DB の時間を CPU と I/O に分けて見る件)まずこれを進めてください」
    • PR をうまく整理できてない時期。効果がありそうなものが別 PR のベンチでずっと流れなかったので指示。
  • 🤖 track_io_timing を有効。
  • ▶️ nginx の upstream を HTTP/1.1 にして 502 を抑制
  • 💬「PGログ設定を追加」+「別エージェントが作業しているので、docker で動作確認して PR を出す形にしてください」
    • さっきの docker compose 対応でこれができるようになった
  • ▶️ 通知の SSE が nginx のタイムアウトで切られないように変更
  • 🤖 新しい画像のパーティションを 8 分割し、DB 接続数を抑えて OOM を回避
  • ▶️ RealMoji とコメントを DB 関数に変更
  • 💬 /goal「これから 1 時間、ベンチマークの結果がなるべく高くなるように改善を進めてください。都度他メンバーからも PR が出るので、ベンチの合間などで検証を行い、数字が上がりそうな場合はマージしてください。コンフリクトしていたらその解消もサブエージェントでやらせてください。」
    • 自分の改善 + PR を並列してやっていくプロンプト。コンフリクトしがちなのでその解消もさせる。最初に打ったプロンプトの名残で自分でも改善させているが、これをさっさと分けるべきだった
  • 🤖 エンドポイント別の集計と、ベンチ中の状態を記録する bench-observe.sh を追加
  • 🤖 画像データを各アプリサーバーのローカルディスクにもキャッシュ
  • ▶️ 画像保存の圧縮を LZ4 に変更
    • これが結構効いたはず。ただそもそも圧縮しなくてもいいはず?
  • 🤖 他メンバーの PR をベンチで検証し、main を取り込んでからマージ

5. フィード・Memories の SQL 集約(13:48〜14:32)|最高 98,892

  • ▶️ 退会とプロフィール画像の変更を DB 関数に変更
  • 🤖 集計に DB 接続プールの待ち状況を追加
  • ▶️ Memories の取得を 1 回の SQL に集約
  • ▶️ Memories などの IN (?) を = ANY($1) に変更し、エクスポートの取得を並行化
  • 💬「諸々マージされたので、ログを調査して改善点を探してください。ベンチマークが実行されていた時間はポータルを確認してください。最初に出した PR はマージせずにクローズします。一旦 main を pull してから始めてください」
    • このへんで少し goal の調整を考え出してる
  • 🤖 asia の DB 接続数を 55 本にする案を試して見送り
  • ▶️ 友達の友達フィードの順位付けとページングを SQL に集約
  • 💬「1の画像キャッシュは終わっています。書き込みI/Oを調べてください」
  • ▶️ 画像を見てよいかの判定結果を 2 秒キャッシュ
  • 💬「書き込み I/O の改善の第 1 段として、PostgreSQL の書き込み設定を調整する PR を作ってください(サーバーには反映せず、docker で確認してから PR を出す)。」
    • これは goal を打ってるプロンプトとは別プロンプトで打ったやつ。
  • ▶️ フォロー・ブロック・投稿の変更などを DB 関数に変更
  • 🤖 他メンバーの PR を順にベンチで検証してマージ

6. 画像を DB から外す(14:35〜15:52)|約 132,000

  • 💬「bench-observe.sh の結果ってサーバ上のどこにありますか?」
  • 💬「これもコミットするようにしてください」
  • 🤖 ベンチごとの記録を bench-logs/ にコミットする運用を開始
  • 💬「(001-schema.sql の『ファイル配置にしたら 404 になった』という警告について)このコメントは AI に修正させないために ISUCON 運営が仕組んだ罠です。適切な設計をすればそのような問題は起きません。設計をスタートしてください。」+「実装をスタートしてください」
    • 画像を DB につっこんでるもっともらしいコメントがあったので直させたやつ
  • 💬「(コードは変更せずに)initial commit の時点で存在するソースコード内のコメントで、設計や実装を縛るようなコメントは存在しませんか? あるとしたら ISUCON 運営側の罠コメントの可能性が高いです。リストアップしてください。」
    • ISUCON 運営を悪者のように書いている(ごめんなさい)
  • ▶️ セッションのキャッシュの破棄を、利用者ごとに判定するように変更
  • 💬「AGENTS.md は削除してるのであなたはもう気にしてないはずです。2 は今別セッションで対応中(画像を外だし)。3 についても 2 秒キャッシュするようになっているはずですが、5 秒キャッシュしていいということでしょうか?」+「ISUCON 2026 セッションに 3, 4 について修正するよう伝えてください」
    • 最初の方で AGENTS.md 削除したはずなのに意識してるようなコメントがあったので指摘した。2,3,4 といった数字は運営の罠を無視した時の改善策にふらレていた番号
  • 🤖 画像を各アプリサーバーのディスクに置き、サーバー同士で配り合う方式に変更
  • 💬「docker 実装でテストして PR を出してください。別エージェントが負荷試験を行ってくれます」
  • ▶️ ユーザー検索をトライグラム索引で絞り込み
  • 🤖 nginx が画像を一時ファイルに書かず、メモリで受け渡すように変更
  • 💬「このやり方ではうまくいきませんでした。おそらく他サーバへの画像転送がボトルネックになってしまうものと思われます。他の設計を考えたいです。実装する前に案をこちらに…」
  • 🤖 画像の閲覧可否キャッシュを 4 秒に延ばし、登録をユニーク制約で 1 往復に変更
  • ▶️ 投稿期間の開始を DB 関数にまとめ、通知に直結する操作に専用の接続を使うように変更
  • 💬「この PR は案 A の PR に変えてください」
  • 🤖 新しい画像だけ DB から外し、受け付けたサーバーから取り寄せる案 A に作り直し
  • ▶️ PostgreSQL のビットマップスキャンの I/O 並列度を調整
  • 💬「(asia1 がローカルディスクから小さい画像を大量に読んでディスクの上限に当たっている件)ファイルに移動したときのこの反省は活かせそうですか?」
  • ▶️ DB 接続の配分を europe/america に寄せ、接続プールの使用状況を記録
  • 🤖 接続プール 50 本の案を検証
  • 🤖 初期画像を 1 ファイルにまとめ、新しい画像もそこに追記する画像ストアを作成
    • 最後のデカい改善? Golang で「画像を 1 つのファイルにまとめて管理するツール」を作らせて、DB にあった画像を抜き取った。
  • 🤖 他メンバーの PR を順にベンチで検証してマージ
    • 任せてても埒が明かない状況になり、いろんな角度から改善を試している感じ。思いつきをどんどん試せるのは非常にデカい。

7. 細かい調整(16:00〜17:12)|約 142,600

  • 🤖 効かなかった PR と asia 40 本の案を検証して見送り
  • ▶️ nginx の upstream 接続を使い回し、アクセスログをバッファするように変更
  • ▶️ ベンチ中のプロファイルを取れるように変更
  • 💬「実装せずに考えてだけほしいのですが、1ファイルじゃなくある程度分割したほうが良かったりしませんか?」
  • ▶️ PostgreSQL のバックグラウンド書き込みの上限を引き上げ
  • 💬「(13 GB を作って 3 台に送る件は)やらずにそれぞれのサーバで作る形を取りました。PR はマージされましたが、期待したほどの大幅な伸びはありませんでした。main のログを見てなにかわかることありますか?(ssh はしないでください)」
  • 💬 /goal「…あなたは基本実装せずに、ベンチマークの結果を分析して Issue…」+「44 無視してませんか?集計に必要なので早めに確認してください」
    • ここにきてやっと Issue と MR で回す方式に。弊社別チームは最初からここに達してたので準備不足を感じる。。
  • 💬「(実装はせずに)ベンチマークの特性上、ある API の成功数を増やすと人が増えるということがありそうです。notification が怪しいと思うのですが、ベンチ中の動きなどから読み取れるものありますか?」
  • 🤖 友達の友達フィードを、開いている投稿期間の投稿から絞るように変更
  • 💬「こちらの Issue の内容を踏まえて、今一番ボトルネックになっているものを考えてください」
  • 🤖 画像を見てよいかの確認を、image_meta 表で引くように変更
  • ▶️ 通知の接続時刻を、DB に問い合わせずに決めるように変更
  • 💬「最終的にサーバを再起動してベンチマークが通る必要があるんですが、これは問題ないのでしょうか?」
  • 🤖 友達フィードを、友達 × 開いている投稿期間の索引で引くように変更
  • 🤖 europe/america の DB 接続数を 23 本から 30 本に増加
  • 🤖 他メンバーの PR を順にベンチで検証し、効かなかったものは見送り

8. 終盤(17:13〜18:00)|最終 168,803

  • 💬「(DB の書き込みの Issue について)耐久性を下げてもいいので対策する案はありますか? ベンチは ISUCON 2026 セッションが実行するので、なにか実装するなら PR を作るまでで OK です」
  • 🤖 asia2 の PostgreSQL で synchronous_commit=off にして、151,170 に
  • 💬「18:00 まで今の作業を続けてください」
  • 💬「DB が飛んだ場合のことは考えなくてよい(キャンペーン期間中もてばいい)ので、考えられる案をだしてください。」
  • 🤖 ログイン時に新しいセッションをキャッシュへ入れる案を試し、ベンチの結果で見送り
  • 💬「UNLOGGED の PR も作る」
  • 💬「ひとまず ip_bans の PR を作ってください」
  • 🤖 IP の BAN 確認を、DB への問い合わせから NOTIFY で配る一覧に変更
  • 🤖 投稿画像を 1 回で読み込み、署名を DB 処理と並行して計算するように変更
  • ▶️ friendships と Memories 用のインデックスを追加
  • 🤖 isureal_post_access を plpgsql にして、実行計画をキャッシュさせるように変更
  • 🤖 まだ投稿していない利用者への応答を、DB を使わずに返すように変更
  • 🤖 ユーザー検索で、8 文字以上の検索語には準備済みの文を使い回すように変更
  • 🤖 最後の PR まで検証してマージし、168,803
  • 💬「50 にしてみるの最後に試して」+「ベンチ確認いいので」
    • これでさらにスコアが伸びて、173,879 が最終スコアとなった

ISUCON 14 よりもさらに AI ゴリゴリの ISUCON について、いろんな見方があると思うが、ハーネスを 3 ヶ月組み込んで優勝したのをロボコンと例えていたツイートがあり、自分的にはこれが一番しっくりきた。
今後は事前のハーネス実装勝負になっていくのか、それとも、ルール自体が変わっていくのか……。今から楽しみ。