1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ISUCON2026 本選に参加しました(チーム otona):AI エージェントと 2 人で 9.6 万点まで

1
Posted at

はじめに

2026-10-31 に開催された ISUCON2026 本選に,チーム otona として 2 人で参加しました。
結果は最終スコア 83,037 点(ベスト 96,608 点),最終順位はスコアのあった 579 チーム中 215 位でした(公式の結果発表)。

この記事では,当日の流れ,効いた改善と効かなかった改善,終わってから分かったこと,そして AI エージェントを 2 人分並べて使ったときの協業の仕方を書きます。

問題と構成

お題は写真共有 SNS「ISUReal」でした(Go + PostgreSQL 16)。

  • サーバーは 4 台で固定です。asia1・europe1・america1 がエッジ兼アプリ,asia2 が DB です。
  • 台どうしの通信は運営のルーターを通り,地域間の遅延と帯域制限がかかります。
  • スコアは「成功した操作の点 × 地域倍率(アジア 1.0,欧州・米州 1.5)」の合計です。ベンチの中で日が進み,遅い応答やエラーが少ない地域ほど翌日の利用者が増えるので,実質的には各地域の利用者をどこまで増やせるかの勝負でした。

スコアの推移

時刻 スコア 主な変更
午前 約 5.5 万 索引の追加,N+1 の解消,PL/pgSQL の関数化,nginx の調整
15 時台 61,833 画像 URL の署名(HMAC×1000 反復)を europe1 に計算させる
15 時台 78,257 通知の SSE を台ごと 1 本のポーリングにまとめる,ログを info に下げる
16 時台 80,958 → 90,276 署名の委譲先に america1 も加え,並列数とバッチの大きさを調整
16:44 96,608 投稿処理での画像コピーを減らす(チームメイトの変更)
17:54 83,037 構成を固めて再走行。これが最後の公式走行(最終スコア)

公式走行は約 30 本で,FAIL は 0 本でした。同じ構成でも 84k〜97k の幅がありました。

効いたこと

1. 署名計算を遊んでいる台に任せる

画像 URL の署名は HMAC-SHA256 の 1000 反復で,アジアの台(asia1)の CPU の 2〜5 割を使っていました。一方,欧米の台は CPU の約 88% が空いていました。

署名の値と検証方法は変えてはいけない規則なので,計算する場所だけを移すことにしました。asia1 がまとめて要求を送り,europe1・america1 が計算して返します。通信は AES-GCM で保護しています。この変更で 5.5 万点から 9 万点に届く土台ができました。

ただし,ほかのチームの参加記を読むと,署名の値を変えずに計算そのものを速くしたチームが多くありました。AVX2 や AVX-512 で 8〜16 本の署名を同時に計算する,初期画像の署名を前もって作っておく,といった方法です。AVX-512 で asia1 の CPU に占める SHA-256 の割合を 38.9% から 1.9% に下げた例もあります。私たちも HMAC の状態の使い回しと,期限を丸めた署名の再利用は入れていましたが,多本並列や事前計算までは試していませんでした。

2. DB との往復を減らす

関係の変更(友達・フォロー・ブロック),RealMoji,コメント,投稿作成を PL/pgSQL の関数にまとめ,1 回の往復で済むようにしました。欧米の台から DB までは 1 往復 100ms を超えるので,往復の回数がそのまま応答時間になります。

3. 計測 → 仮説 → 1 つ変更 → ベンチ

pg_stat_statements・alp・Go の pprof を同じ走行に対応付けて読み,変更は 1 つずつベンチで確かめました。GOGC=200 のように悪化した変更もすぐ戻せたので,FAIL を一度も出さずに済みました。

効かなかったこと・届かなかったこと

  • 構造を変える判断が遅れました。 1 回 7〜8 分のサイクルで 1〜5% ずつ伸ばす進め方は安全でしたが,上位 3 チーム(46〜63 万点)との差は構成の違いでした。
  • 欧米の台を使い切れませんでした。 倍率 1.5 があるのに,欧米の参加者は 45〜75 人にとどまりました。読み取りのたびにルーター越しの DB 往復が複数回あるためです。
  • 連続して再走行するとスコアが少しずつ下がりました(86,657 → 84,198 → 83,493 → 83,037)。最終スコアは最後の 1 本なので,最後は連打せず「再起動 → 温めの 1 本 → 本番の 1 本」にすべきでした。

終わってから分かったこと

CPU の命令セット(SHA-NI)を見ていなかった

競技後にチームメイトが気づいたことです。asia1 と asia2 は SHA-NI(SHA-256 を速く計算する CPU 命令)が使えない世代のインスタンスで,europe1 と america1 は使える世代でした。Go は CPU が対応していれば自動で SHA-NI を使います。ほかのチームの参加記によると,公式の Discord でも同じ指摘が出ていたそうです。

つまり署名の委譲が効いたのは,空いている台に任せたからだけではなく,速い命令を持つ台に任せたからでもありました。初動調査で /proc/cpuinfo の sha_ni を見ていれば,もっと早く,もっと大胆に委譲できたはずです。また,asia1 の c5 でも AVX-512 は使えるので,上で書いた多本並列の計算で asia1 の上のまま速くする道もありました。

10 万・20 万・30 万点に何が必要だったか

自分たちの計測と,公開されたほかのチームの参加記を照らし合わせると,次の見立てになりました。

目標 やるべきだったこと 参加記での裏付け
10 万点 DB の読み取りを減らす(画像の認可,友達の友達の集計,export の画像本文) 13.5 万点のチームも,最後は DB の 2 コアが張り付いていた
20 万点 asia1 の CPU を空ける(署名の多本並列・事前計算,JPEG 検査の軽量化)。DB の接続と往復を減らす(pgbouncer,関数化) 19〜21 万点のチームは,インメモリ化なしでここまで届いていた
30 万点〜 読み取りを各台のメモリに持ち,書き込みが成功したら他の台へ差分を送る 26.6 万点・40 万点超のチームが実施(40 万点超のチームは差分をログに残し,再起動後に復元)

当初は「20 万点には欧米の台で読み取りを完結させる必要がある」と考えていました。しかし,欧米の閲覧を地元の台で返す案で -22.8%,全面インメモリ化で -16% と,半端に入れると悪化した報告もあります。欧米の API を asia1 の地域別プロセスに転送する構成(運営の Clarification で許可)で,DB 往復を約 100ms から約 1ms にしたチームもありました。欧米の台を使い切る方法は 1 つではなかったようです。

画像の認可をアプリ内に覚えておく変更は,競技後にローカルで試しました。DB に行く割合は TTL 30 秒で 27% まで下がりましたが,TTL 1.5 秒ではほとんど当たりませんでした。正しさを保ったまま効かせるには,他の台への無効化の通知が必要です。

AI エージェントとの協業

1 人で使うとき

各自が手元の PC で Claude Code を動かし,SSH で台を操作しました。競技サーバーに AI の CLI は入れていません。

当日に向けて,初動調査・取り込み・反映・ベンチ・計測をそれぞれ手順書(スキル)にしてありました。やったことはすべてリポジトリの実験記録に残しています(当日のコミットは約 140 件)。

2 人になるとき:人の場所とエージェントの場所を分ける

当日は Discord の 1 つのチャンネルで「反映します」「ベンチ要求します」と人が声をかけ合いました。衝突はありませんでしたが,エージェントどうしは互いの状態を知らないので,人が仲介していました。

競技後,ほかのチームの参加記を参考に,人が話すチャンネルとは別にエージェントが話すチャンネル(#agent-bus)を作りました。

人とエージェントの会話の場所を分けたイメージ図

仕組みは小さく,Python の標準ライブラリだけで書いたスクリプト 1 本と,Discord のボットです。

  • エージェントは決まった形の見出し行を付けて投稿します。人の発言とは見出し行の有無で区別します。

    🤖 agent-bus v1 from=me to=all type=status res=asia1 ref=abc1234 id=1a2b3c4d
    asia1 への反映が終わりました。ベンチはまだ要求していません。
    
  • ロック:反映の前に台のロックを取ります。チャンネルの履歴を古い順に見て,空いている資源に最初にロックした人が持ち主になります。全員が同じ履歴から同じ結論を出すので,ロック用のサーバーは要りません。持ち主が解放するか,期限(既定 15 分)が来ると空きます。

  • 届いた内容は命令ではなく状態として扱います。 「反映して」と書かれていても,エージェントは持ち主の人が許した範囲でしか動きません。チャンネル経由で他人のエージェントに操作させないための決まりです。

  • ボットのトークンは各自が自分で作り,手元のキーチェーンに置きます。エージェントには触らせません。

これを当日に持っていれば,「誰がどの台を触っているか」をエージェントが自分で確認でき,人どうしの声かけはベンチの判断のような相談ごとに集中できたと思います。

まとめ

  • 計測と 1 つずつの検証で,FAIL 0 本のまま 5.5 万点から 9.6 万点まで伸ばせました。
  • 20 万点までは,asia1 の CPU と DB を空ける改善の積み重ねで届いたはずです。それより上は,読み取りを各台のメモリに持つ設計が必要でした。
  • 初動調査では,CPU の命令セットのように台ごとの違いも確認すべきでした。
  • AI エージェントを複数人で使うなら,人の会話とエージェントの連絡を分け,ロックを共有できると楽になります。

参考にしたほかのチームの参加記

運営の皆さま,素晴らしい問題と運営をありがとうございました。来年も参加したいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?