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?

去年の正解が、今年の間違いになる

1
Last updated at Posted at 2026-08-03

この記事は、自社ブログの LYR Performance Note #002 に掲載したものの転載です。

同じ計測をやり直したら、ボトルネックは動いていた

数か月後に同じ計測をやり直したら、内訳は真逆になっていた。生成は全体の1割。残る9割は、待ち行列と距離だった。

前回いちばん効いたレバーは、もう的外れだった。ボトルネックは動く——正解には賞味期限がある。

そこで往復を消そうとユーザーの近くでの推論(エッジ推論)を試すと、今度は全体が3倍遅くなった。部分最適は、全体では負ける。

前回、遅さの原因はモデルの生成——正確には、モデルが答える前に"考えて"いたことだった、と書いた。思考をオフにして(reasoning=none)、生成は一気に軽くなった。当時はそれで十分だった。

問題は、正解に賞味期限があることだ。

習慣が、昔の結論を疑わせる

一度「分解して測る」を覚えると、それが癖になる。別の作業のついでに、私はまた同じ内訳計測を回した。深い意図はなく、ただ「いまはどうなってるか」を見たかっただけだ。

出てきた数字を見て、手が止まった。

区間 p50 割合
ネットワーク往復 275 ms ~55%
queue(待ち行列) 167 ms ~33%
生成(generation) 50 ms ~10%
prompt(入力処理) 7 ms ~1%

かつて時間を支配していた生成が、いまや10%まで縮んでいた。しかも新旧2機種(各38サンプル)でほぼ一致しているので、これは測定ノイズではなく構造だ。

理由はすぐ分かった。前回モデルの"考え"を止め、その後も出力を絞り込んで、生成そのものが軽くなっていた。生成を軽くしたぶん、相対的に「待ち」と「距離」が浮上したのだ。支配項が入れ替わっていた。

待ち行列は、平均で語ってはいけない

さっきの167msは、待ち行列の中央値にすぎない。そして待ち行列は、平均で語ってはいけないものの典型だった。それを痛感したのは、いまの現行モデルではなく、その一つ前に本番候補だった別のモデルでのことだ。

そのモデルは、共有インフラ上の巨大なモデルだった。混雑時に、同じ待ち行列を測ると——中央値からして、桁が違った

パーセンタイル 待ち行列(別モデル・混雑時)
p50(中央値) 988 ms
p90 3,438 ms
p99 4,883 ms

このモデルは、中央値ですでに約1秒——現行モデル(167ms)の、およそ6倍だ。そして100回に1回は、約5秒待たされる。しかも厄介なのは、いつそうなるかが読めないことだ——空いている時間帯なら150ms、混雑すればこの分布。「いつも速い」でも「いつも遅い」でもなく、読めない

平均だけ見ていたら、このテールはまったく見えない。だが、ユーザーが覚えているのは平均ではなく、その最悪の一回だ——マニフェストの3番目の原則——良い代理指標は、平均でなく最悪の一回(tail)を見る——そのものである。そしてこのテールは、外部の共有インフラを使う限り消せない——並ぶ相手を、こちらは選べないからだ。(専有すれば、このテールごと消える。それが第5回。)

ネットワークの275msをさらに分解すると、接続はコネクションプールで再利用されていて確立コストはほぼゼロ、応答も小さく転送も一瞬。つまり275msはほぼ純粋な地理的往復——端末から遠い場所(当時は米国)にある推論サーバまでの、物理的な往復時間だった。(世界各地のAWSリージョンで実測した詳細は、深掘り「地理は、レイテンシの動かせない床だ」に。)

だから、打つべきレバーも入れ替わる

前回の正解「モデルに考えさせない」は、もうこれ以上は効かない。10%しかない生成をどういじっても、体感はほとんど動かない。いま支配的なのは、

  • 距離(往復275ms)→ 推論をユーザーの近くに置けば消える。この275msは、動かせない物理の"床"だ
  • queue(167ms)→ 共有インフラの待ち行列。専有すれば消える

つまりレバーは「モデルを速く」でも「出力を削る」でもなく、推論サーバーを物理的に近く・専有で持つことに移っていた。

仮説を検証する(そして、また負ける)

「往復さえ消せば速くなる」なら、ユーザーの近くのエッジで推論すればいい。都合よく、あるエッジ推論サービスにまったく同じモデルが載っていた。すでにそのエッジ基盤を経由していたので、叩き先を差し替えるだけで比較できる。理屈の上では完璧だった。

結果はこうだ。

経路 翻訳 wall p50 max 結果
現行(遠いが専用の高速推論) 502 ms ✅ 字幕が出る
エッジ推論(近いが汎用GPU・同一モデル) 1500 ms(制限時間に到達) 2610 ms ❌ 字幕が出ない

決定的な負け。往復を250msも消したのに、全体は遅くなった。

原因は、分解表のおかげで即座に判明した。近くても、エッジの汎用GPUでは生成が間に合わなかった。暖機後の純粋な生成でも現行より遅く(測れた範囲で約1.5倍)、実運用ではコールドスタートや待ちも重なって、翻訳が終わる前に制限時間(1500ms)で打ち切られた——だから字幕が出ない。表の「1500ms」は生成の速さではなく、クライアント側の制限時間そのものだ。往復をいくら消しても、生成が締め切りを越えれば、全体では負ける。10%まで小さくなっていたはずの生成が、遅いハードに載せた瞬間に勝敗を決めたのだ。

唯一の出口は「近い×速い」の両立

ここで、前回のもうひとつの教訓が効いてくる。部分最適は罠だ。往復だけ消しても、生成が遅ければ意味がない。逆に、生成だけ速くても、遠ければ意味がない。

だから条件は「近接かつ高速推論」の両立になる。試算では、専用の高速チップをユーザーに近い地域(例:国内)に置ければ、往復は十数ミリ秒、全体は100ms前後まで落ちる見込みだった。これが、自前で推論を持つ(セルフホスト)を検討し始めた本当の起点だ。速いモデルが欲しかったのではない。近くて速い場所が欲しかった。

(では、なぜ最初から自前にしなかったのか——それは供給側の事情という別の物語で、第4回に続く。)

教訓

  1. ボトルネックは動く。だから測り続ける。 一度の分解で得た正解は、状況が変われば失効する。ズレに気づけたのは計測が習慣になっていたからで、前回の結論を「もう分かったこと」として棚に上げていたら、いまも効かないレバーを引いていた。
  2. 相対値で考える。 生成が「軽くなった」のではなく、他が相対的に「重くなった」。支配項は、絶対値でなく割合で入れ替わる。
  3. 部分最適は罠。 往復を消しても生成が遅ければ逆効果。全体(end-to-end)で、複数の区間を同時に満たさないと勝てない。

付録:生データ

項目 実測 条件・留保
翻訳 wall p50 502ms Pixel 10 / 7a 各 n=38、cross-device で一致
内訳(P10 / 7a) ネットワーク往復 275 / 268ms、queue 167 / 200ms、generation 50 / 66ms、prompt 7ms 生成は全体の約1割
ネットワーク内訳 接続はプール再利用で +0〜2ms、転送 +1〜3ms 275ms は純・地理往復
エッジ推論 A/B(同一モデル) wall p50 1500ms(全サイクルが上限に到達)/ max 2610ms(現行 502ms) 暖機後でもエッジ生成は現行の約1.5倍遅い
近接×高速の試算 往復 ~13ms、全体 ~97ms 体感の壁 ~177ms を初めて下回る見込み(試算)

シリーズ「計測が導いた旅」第2回の記事です。原文と続きは LYR Performance Note #002 / 記事一覧 にあります。

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?