負荷分散と複数キー戦略
複数のAPIキーとアカウントに対してラウンドロビンおよび重み付き負荷分散を実装し、レート制限の余裕を増やしてp99レイテンシの急増を抑えます。
「負荷分散と複数キー戦略」はCoddyKit上の無料AI Engineering Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Engineering Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Engineering Academyコースには全4レッスンが含まれています。
API キーが 1 つでは不十分な理由
1 つの OpenAI API キーには、1 分あたりのリクエスト数(RPM)と 1 分あたりのトークン数(TPM)で測定される固定のレート制限があります。Tier 1 では、GPT-4o は 500 RPM と 30,000 TPM を許可しています。数百人のユーザーが同時に利用する本番アプリケーションでは、1 つのキーは常にこれらの制限に達してしまいます。複数の API キーを使えば、利用可能な余裕を比例して増やせます。
複数の API キーを作成する
1 つの OpenAI organization 内に複数の API キーを作成するか、複数の OpenAI アカウント(それぞれ個別に課金されます)を作成できます。各キーを環境設定に保存し、プールとして扱ってください。キーは、ソースコードやバージョン管理にコミットする .env ファイルではなく、AWS Secrets Manager や HashiCorp Vault などのシークレットマネージャーで管理してください。
import os
API_KEYS = [
os.environ['OPENAI_KEY_1'],
os.environ['OPENAI_KEY_2'],
os.environ['OPENAI_KEY_3'],
os.environ['OPENAI_KEY_4'],
]
# Total effective RPM = 500 * 4 = 2000 RPM
# Total effective TPM = 30000 * 4 = 120000 TPMラウンドロビンによるロードバランシング
ラウンドロビンでは、すべてのキーを順番に循環してリクエストを均等に分散します。実装が簡単で、時間の経過とともに各キーがほぼ同じ負荷を処理することを保証できます。同時実行される 2 つのリクエストが同じキーを同時に選ばないように、スレッドセーフなカウンターまたはアトミック整数を使用してください。すべてのキーのレート制限が同一の場合、ラウンドロビンが適しています。
import itertools
import threading
from openai import OpenAI
class RoundRobinPool:
def __init__(self, keys: list):
self._clients = [OpenAI(api_key=k) for k in keys]
self._cycle = itertools.cycle(range(len(self._clients)))
self._lock = threading.Lock()
def get_client(self) -> OpenAI:
with self._lock:
idx = next(self._cycle)
return self._clients[idx]
pool = RoundRobinPool(API_KEYS)
client = pool.get_client()重み付きロードバランシング
重み付きロードバランシングでは、より高いレート制限を持つ上位 Tier のキーに、容量に比例して多くのトラフィックを割り当てます。キー A が Tier 3(10,000 RPM)、キー B が Tier 1(500 RPM)の場合、キー A には約 95% のリクエストを割り当てるべきです。重み付けによる分散により、下位 Tier のキーが上位 Tier のキーと混在した際にボトルネックになるのを防げます。
import random
class WeightedPool:
def __init__(self, key_configs: list):
# key_configs = [{'key': '...', 'weight': 10}, ...]
self._clients = [OpenAI(api_key=c['key']) for c in key_configs]
self._weights = [c['weight'] for c in key_configs]
def get_client(self) -> OpenAI:
return random.choices(self._clients, weights=self._weights, k=1)[0]
pool = WeightedPool([
{'key': os.environ['OPENAI_KEY_TIER3'], 'weight': 20},
{'key': os.environ['OPENAI_KEY_TIER1'], 'weight': 1},
])キーごとのレート制限状態を追跡する
OpenAI API はすべてのレスポンスでレート制限ヘッダーを返します。x-ratelimit-remaining-requests と x-ratelimit-remaining-tokens です。キーごとにこれらのヘッダーを追跡し、どのキーが上限に近づいているかを把握してください。現在の 1 分間に残っているリクエスト数が 10 未満になったキーについては、429 エラーが発生する前に、一時的にそこへのトラフィックを止めてください。
class SmartPool:
def __init__(self, keys: list):
self._clients = [OpenAI(api_key=k) for k in keys]
self._remaining = {i: 500 for i in range(len(keys))} # initial RPM
def get_best_client(self):
# Pick key with most remaining capacity
best_idx = max(self._remaining, key=lambda i: self._remaining[i])
return self._clients[best_idx], best_idx
def update_remaining(self, idx: int, response_headers: dict):
remaining = int(response_headers.get('x-ratelimit-remaining-requests', 0))
self._remaining[idx] = remaining429 レート制限エラーに対処する
キーが 429 エラーを返した場合は、Retry-After ヘッダーで指定された期間(通常は 60 秒)の間、直ちにそのキーをプールから外してください。そのキーをクールダウン中としてマークし、残りのキーにすべてのトラフィックを振り分けます。クールダウン期間が終わったら、キーをプールに戻します。これにより、同じキーへのリトライによって状況が悪化する連鎖的な障害を防げます。
import time
from openai import RateLimitError
class CooldownPool:
def __init__(self, keys: list):
self._clients = [(OpenAI(api_key=k), None) for k in keys] # (client, cooldown_until)
def get_available_clients(self):
now = time.time()
return [
(i, c) for i, (c, until) in enumerate(self._clients)
if until is None or until <= now
]
def mark_cooling(self, idx: int, retry_after: int = 60):
client, _ = self._clients[idx]
self._clients[idx] = (client, time.time() + retry_after)
print(f'Key {idx} cooling down for {retry_after}s')OpenRouter をマルチプレクサーとして使う
OpenRouterは、単一の OpenAI 互換 API エンドポイントを通じて数百のモデルを公開するプロキシサービスです。OpenRouter 経由でルーティングすると、複数の基盤プロバイダーアカウント間でのロードバランシング、代替プロバイダーへのフォールバック、バックアップとしてのオープンソースモデルへのアクセスを自動的に利用できます。得られる運用上のシンプルさを考えれば、コストの上乗せはわずかです。
from openai import OpenAI
# OpenRouter uses the same OpenAI SDK interface
client = OpenAI(
api_key=os.environ['OPENROUTER_API_KEY'],
base_url='https://openrouter.ai/api/v1'
)
response = client.chat.completions.create(
model='openai/gpt-4o', # OpenRouter model name format
messages=[{'role': 'user', 'content': prompt}]
)
# Automatic failover if OpenAI is downメトリクスでキーの健全性を監視する
送信したリクエスト数、受信した 429 エラー数、過去 1 時間のクールダウン時間など、キーごとのメトリクスを追跡してください。429 の割合が高いキーには、トラフィックの削減または Tier の引き上げが必要です。これらのメトリクスを Prometheus 形式で /metrics エンドポイントに公開し、いずれかのキーが継続的に制限に達しているときに監視システムがアラートを出せるようにしてください。
from dataclasses import dataclass, field
from collections import defaultdict
@dataclass
class KeyMetrics:
requests_sent: int = 0
rate_limit_errors: int = 0
total_tokens_used: int = 0
cooldown_count: int = 0
class MetricPool:
def __init__(self, keys: list):
self._clients = [OpenAI(api_key=k) for k in keys]
self._metrics = [KeyMetrics() for _ in keys]
def report(self):
for i, m in enumerate(self._metrics):
error_rate = m.rate_limit_errors / max(m.requests_sent, 1)
print(f'Key {i}: {m.requests_sent} req, {error_rate:.1%} 429 rate')地域ごとのキー分散
ユーザーが世界中に分散している場合は、地理的リージョンごとに個別の API キーを用意し、ユーザーに最も近いキーへリクエストをルーティングすることを検討してください。ネットワークのラウンドトリップ時間が短くなるため、TTFT が改善します。各リージョンに軽量なロードバランサー(AWS Lambda@Edge または Cloudflare Worker)を配置し、適切なキーを選択してリクエストをプロキシすれば、クライアントからキーを隠せます。
REGIONAL_KEYS = {
'us-east': os.environ['OPENAI_KEY_US_EAST'],
'eu-west': os.environ['OPENAI_KEY_EU_WEST'],
'ap-southeast': os.environ['OPENAI_KEY_AP'],
}
def get_key_for_region(user_region: str) -> str:
# Default to us-east if region unknown
return REGIONAL_KEYS.get(user_region, REGIONAL_KEYS['us-east'])ロードバランサーをテストする
バランシングプールを通じて 100 件の同時リクエストを送信し、分散状況、エラー率、レイテンシのパーセンタイルを測定する負荷テストを作成してください。1 つのキーが比例配分を超えるリクエストを処理していないこと、429 エラーが 0.1% 未満であることを確認します。asyncio.gather または Locust のようなツールを使って、本番システムで実際に発生する同時負荷をシミュレートしてください。
import asyncio
import time
async def load_test(pool, concurrency=100, total=1000):
sem = asyncio.Semaphore(concurrency)
results = []
async def one_request():
async with sem:
client = pool.get_client()
start = time.perf_counter()
try:
await client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': 'Ping'}],
max_tokens=5
)
results.append(('ok', time.perf_counter() - start))
except Exception as e:
results.append(('error', str(e)))
await asyncio.gather(*[one_request() for _ in range(total)])
ok = [r for r in results if r[0] == 'ok']
print(f'Success rate: {len(ok)/total:.1%}')
return results適切なバランシング戦略を選ぶ
レート制限の構成に合わせてバランシング戦略を選択してください。すべてのキーの Tier 制限が同一で、トラフィックが均等に分散される場合はラウンドロビンを使います。キーごとに Tier 制限が異なる場合は重み付き分散を使います。バーストトラフィック下で 429 エラーを最小限に抑える必要がある場合は、上限に近いキーをスキップするヘルス対応ルーティングを使います。ほとんどの本番システムでは、指数バックオフと組み合わせたヘルス対応ルーティングが、シンプルさと耐障害性のバランスに最も優れています。
# Strategy selection guide:
# Scenario A: 4 keys all Tier 2 (same limits)
# -> Round-robin: simple, even distribution
#
# Scenario B: 1 Tier 3 key + 3 Tier 1 keys
# -> Weighted: Tier 3 gets 10x weight
#
# Scenario C: Variable traffic with burst periods
# -> Health-aware: track remaining headers, skip near-limit keys
#
# Scenario D: Multi-region, latency-sensitive
# -> Geographic: regional keys, route by user locationクイックチェック
LLM API のロードバランシング戦略についての理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、ラウンドロビンと重み付き分散によって複数の API キーにトラフィックを分散し、レート制限の余裕を増やせること、クールダウンの追跡によって制限に達したキーを一時的に除外し、429 エラーの連鎖を防げること、そしてOpenRouterが自動フォールバック機能を備えたマネージドなマルチプレクシングの選択肢を提供することを学びました。次は、フォールバックプロバイダーとサーキットブレーカーを実装します。
よくある質問
「負荷分散と複数キー戦略」レッスンは無料ですか?
はい。「負荷分散と複数キー戦略」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Engineering Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Engineering Academyコースには全4レッスンが含まれています。
「負荷分散と複数キー戦略」で何を学びますか?
複数のAPIキーとアカウントに対してラウンドロビンおよび重み付き負荷分散を実装し、レート制限の余裕を増やしてp99レイテンシの急増を抑えます。 ブラウザで直接実行するハンズオンコードでAI Engineering Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Engineering Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Engineering Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「負荷分散と複数キー戦略」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Engineering Academyレッスンでコードを書いて実行できますか?
はい。すべてのAI Engineering Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。