GEMINI LABEN
API — Gemini APIのスループットが毎分160億トークン超となり、OpenAIとほぼ肩を並べる規模になりましたENTERPRISE — Gemini Enterpriseの有料シートが800万を超え、導入企業は2,800社超に拡大していますAGENT — Claude Opus 4.8がGemini Enterprise Agent Platformで利用可能になり、マルチベンダー化が進んでいますSPEECH — gemini-3.1-flash-tts-previewがstreamGenerateContentでストリーミング音声生成に対応しましたDATA — CrossbeamデータストアをGemini Enterpriseへ接続できる公開プレビューが始まりましたMODEL — Gemini 3.5 FlashのGAとGemma 4の提供で、エージェント用途と軽量用途の選択肢が揃いましたAPI — Gemini APIのスループットが毎分160億トークン超となり、OpenAIとほぼ肩を並べる規模になりましたENTERPRISE — Gemini Enterpriseの有料シートが800万を超え、導入企業は2,800社超に拡大していますAGENT — Claude Opus 4.8がGemini Enterprise Agent Platformで利用可能になり、マルチベンダー化が進んでいますSPEECH — gemini-3.1-flash-tts-previewがstreamGenerateContentでストリーミング音声生成に対応しましたDATA — CrossbeamデータストアをGemini Enterpriseへ接続できる公開プレビューが始まりましたMODEL — Gemini 3.5 FlashのGAとGemma 4の提供で、エージェント用途と軽量用途の選択肢が揃いました
記事一覧/高度な活用
高度な活用/2026-07-03上級

夜間バッチが朝の 429 を連れてくる — 1 プロジェクト内で対話機能の Gemini クォータを守る優先度つきアドミッション制御

同一プロジェクトの RPM/TPM をバルク処理と対話機能が奪い合う問題を、機能タグつき計測と優先度つきトークンバケットで解消した設計と実測を記録します。429率3.2%→0.03%。

Gemini API164レート制限4アーキテクチャ9トークンバケット運用設計8プロダクション6

プレミアム記事

朝 8 時台に、ユーザー向けの生成機能だけ 429 が集中して出る。そんな症状に気づいたのは、アプリ内説明文の多言語一括再生成ジョブを夜間に流し始めてから 3 日目のことでした。ジョブ自体は深夜 2 時開始の設計だったのですが、対象件数が増えて処理が朝まで食い込み、利用者が増え始める時間帯とバルク処理の尻尾が重なっていたのです。個人開発では 1 つの Google Cloud プロジェクトに複数の機能を同居させることが多く、この「機能同士がクォータを奪い合う」構図は遅かれ早かれ踏む問題だと思います。

Gemini API のレート制限(RPM・TPM)はモデルごと・プロジェクトごとに適用されます。つまり同じプロジェクトから呼んでいる限り、ユーザーが画面の前で待っている対話機能も、遅れても誰も困らない夜間バッチも、同じ 1 つの枠を食べます。今回はこの契約を前提に、対話機能を保護する側に倒したアドミッション制御の設計と、導入前後の実測を記録します。

症状の切り分け — その 429 は「誰が」使い切った枠なのか

429 対策というとリトライ戦略の話になりがちですが、リトライは「枠が回復すれば通る」ことを前提にした対処です。枠そのものを別の機能が継続的に消費している場合、リトライは行列を長くするだけで、むしろリトライ増幅で消費を加速させます。リトライ可能かどうかの分類は429 の原因別リトライ設計の記事に書いたので、今回はその手前、「そもそも枠を誰が食べているか」から始めます。

私自身が最初にやったのは、すべての Gemini 呼び出しに機能タグを通すことでした。呼び出し箇所が散らばっていると集計のしようがないので、まず薄いラッパーに寄せます。

import time
import threading
from collections import defaultdict, deque
from google import genai
 
client = genai.Client()
 
class TaggedGeminiClient:
    """全呼び出しに feature タグを強制し、分単位の使用量を記録する薄いラッパー"""
 
    def __init__(self, client: genai.Client):
        self._client = client
        self._lock = threading.Lock()
        # feature -> deque[(epoch_minute, requests, tokens)]
        self._usage = defaultdict(lambda: deque(maxlen=180))
 
    def generate(self, *, feature: str, model: str, contents, config=None):
        resp = self._client.models.generate_content(
            model=model, contents=contents, config=config
        )
        used = resp.usage_metadata
        total = (used.prompt_token_count or 0) + (used.candidates_token_count or 0)
        minute = int(time.time() // 60)
        with self._lock:
            bucket = self._usage[feature]
            if bucket and bucket[-1][0] == minute:
                m, r, t = bucket[-1]
                bucket[-1] = (m, r + 1, t + total)
            else:
                bucket.append((minute, 1, total))
        return resp
 
    def snapshot(self, last_minutes: int = 60):
        """直近 N 分の feature 別 RPM / TPM を返す"""
        cutoff = int(time.time() // 60) - last_minutes
        out = {}
        with self._lock:
            for feature, buckets in self._usage.items():
                rows = [b for b in buckets if b[0] >= cutoff]
                if rows:
                    out[feature] = {
                        "avg_rpm": sum(r for _, r, _ in rows) / len(rows),
                        "peak_rpm": max(r for _, r, _ in rows),
                        "peak_tpm": max(t for _, _, t in rows),
                    }
        return out

usage_metadata を集計に使うので、追加コストなしで実トークン量まで取れます。これを 1 週間流した結果が次の表です。朝 7〜9 時のピーク帯で、バルク再生成が RPM の 82% を占めていました。対話機能の 429 は「対話機能が増えたから」ではなく、「バルクの尻尾が朝に届いていたから」だったわけです。

機能呼び出しパターンピーク帯 RPM 占有許容できる遅延
対話生成(ユーザー向け)朝夕にスパイク14%数秒(体感に直結)
多言語説明文の一括再生成夜間開始・完了まで数時間82%数時間(誰も待っていない)
通知文の下書き生成散発4%数分

この表の「許容できる遅延」の列が設計のすべてです。遅延許容度がまったく違う仕事が同じ枠を同じ優先度で食べていることが問題であって、枠の総量が足りないわけではありませんでした。

Before/After — 素通しの呼び出しをアドミッション層に通す

対策前の構成は、各機能がそれぞれ SDK を直接呼ぶ素直な形でした。

# Before: 各機能が好きなタイミングで直接叩く
# 対話ハンドラ
resp = client.models.generate_content(model="gemini-flash-latest", contents=user_prompt)
 
# バルクワーカー(ループで数千件)
for item in items:
    resp = client.models.generate_content(model="gemini-flash-latest", contents=build_prompt(item))

この形の何が問題かというと、API 側のレートリミッタに到達して初めて「混んでいる」ことが分かる点です。429 を受け取った時点では、もう対話リクエストとバルクリクエストの区別はつきません。先に自分のプロセス側で交通整理をする、つまり呼び出しの手前に admission control(入場制御)を置くのが After の形です。

# After: 全呼び出しが優先度つきの入場ゲートを通る
gate = PriorityAdmissionGate(rpm_limit=1000, tpm_limit=1_000_000,
                             reserved_interactive_ratio=0.3)
 
# 対話ハンドラ
async with gate.acquire(feature="chat", priority="interactive", est_tokens=1200):
    resp = await async_generate(user_prompt)
 
# バルクワーカー
async with gate.acquire(feature="bulk_regen", priority="bulk", est_tokens=2800):
    resp = await async_generate(build_prompt(item))

ゲートの契約は 2 つだけです。対話用に枠の一定割合(ここでは 30%)を常に予約しておくこと。そしてバルクは残りしか使えないが、対話が暇なときはその予約分を借りてよいこと。逆方向の貸し借り(バルクが対話の予約を食う)は許しません。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
機能タグつき計測で「どの機能が RPM/TPM を食べているか」を特定する実装と、バルクがピーク時 82% を占めていた実測の読み方
対話枠を予約しバルクは残りを使う優先度つきトークンバケット(RPM と TPM の二次元制御)の動く Python 実装
対話機能の 429 率 3.2%→0.03% の導入実測と、「別 API キーではクォータ隔離にならない」等の見落としやすい運用判断
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

高度な活用2026-05-31
Gemini Embedding モデルを切り替える日:無停止リインデックスの設計
埋め込みモデルを新しくすると、過去に作った全ベクトルが使えなくなります。サービスを止めずに数十万件のベクトルを作り直す二重インデックス方式を、再開可能な再生成ジョブとクエリ側の抽象化層のコード付きで設計します。
高度な活用2026-05-24
SwiftData × Gemini API オフラインキャッシュ設計 — レスポンスを永続化して再利用するアーキテクチャ
SwiftData で Gemini API レスポンスを永続化し、機内モードや低速回線でも前回の結果を再利用できる iOS アプリ向けのキャッシュ層を設計します。@Model 設計、無効化戦略、サイズ管理、移行手順までを実装ベースで整理しました。
高度な活用2026-04-07
Gemini 2.5 Flash Thinking — 思考プロセスの可視化と高度推論を本番システムに組み込む
Gemini 2.5 Flash Thinking Experimental の思考トレース機能・高度推論能力をAPIから活用する完全ガイド。コスト最適化・思考バジェット設定・ストリーミング対応まで実装例付きで解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →