コンテンツにスキップ
OmniRoute source

Redis Production Configuration Guide (日本語)

現在の設定(コード上のデフォルト)

Section titled “現在の設定(コード上のデフォルト)”
設定 値 定義場所
REDIS_URL 環境変数 redis://redis:6379(compose)、任意 rateLimiter.ts:5, .env.example
REDIS_KEY_PREFIX 環境変数 omniroute:(デフォルト) rateLimiter.ts, redisQuotaStore.ts, redisCircuitBreakerStore.ts, .env.example
QUOTA_STORE_REDIS_URL 環境変数 個別に設定でき、REDIS_URL と異なる値も指定可能 quota/storeFactory.ts
QUOTA_STORE_DRIVER "sqlite"(デフォルト)、任意で "redis" quota/storeFactory.ts
ioredis maxRetriesPerRequest 3 rateLimiter.ts のクライアント作成処理
enableReadyCheck 未設定(ioredis のデフォルト: true) —
lazyConnect 未設定(ioredis のデフォルト: false) —
retryStrategy 未設定(ioredis のデフォルト: ベース 200ms、指数バックオフ) —
TLS / パスワード / DB インデックス 未設定 —
Sentinel / Cluster 未設定 — スタンドアロンの単一ノードのみ —

OmniRoute は、ホスト上で稼働する他のサービスと Redis インスタンスを共有します。名前空間がない場合、auth:api_key:<sha256> や rl:* などのキーが、同じ Redis を使用する他のアプリケーションのキーと衝突する可能性があります(このインスタンスでは、他のサービスとともに Redis が 127.0.0.1:6379 で稼働します)。

すべての OmniRoute キーにプレフィックスを付けるには、REDIS_KEY_PREFIX に空でない文字列を設定します。

ターミナルウィンドウ
# .env — すべての OmniRoute キーは omniroute:rl:*、omniroute:auth:*、omniroute:quota:*、omniroute:warmup:cb:* になります
REDIS_KEY_PREFIX=omniroute:
  • デフォルト: omniroute:(REDIS_KEY_PREFIX が未設定または空の場合に適用)。
  • 適用対象: レートリミッターと認証キャッシュ(keyPrefix を介して共有される ioredis クライアント)、クォータストア(KEY_PREFIX = "${REDIS_KEY_PREFIX}quota")、およびウォームアップ用サーキットブレーカー(KEY_PREFIX = "${REDIS_KEY_PREFIX}warmup:cb:")。
  • Redis にキーがすでに存在する状態でプレフィックスを変更すると、古いキーは孤立します(TTL / LRU によって期限切れになります)。安全に変更でき、移行は不要です。唯一の例外は、禁止としてマークされた接続に対応するウォームアップ用サーキットブレーカーキーです。このキーは TTL なしで永続化されるため、redis-cli --scan --pattern '<old-prefix>warmup:cb:*' で残存キーを一覧表示し、削除してください。
  • ioredis の keyPrefix は、書き込み時にプレフィックスを自動的に追加し、読み取り時に自動的に取り除くため、アプリケーションコードからプレフィックスが見えることはありません。

推奨される本番環境向けチューニング

Section titled “推奨される本番環境向けチューニング”

1. コネクションプール / クライアントオプション(ioredis の Redis コンストラクター)

Section titled “1. コネクションプール / クライアントオプション(ioredis の Redis コンストラクター)”

現在のコードでは、カスタムオプションなしで単一の new Redis(url) を作成しています。本番環境の マルチレプリカ構成では、コード内でクライアントファクトリを渡すか、getRedisClient() をラップしてください。

const redis = new Redis(REDIS_URL, {
maxRetriesPerRequest: null, // 再試行回数を制限せず、retryStrategy に判断を委ねる
enableReadyCheck: true, // 呼び出しを受け付ける前にサーバーの準備完了を確認する
lazyConnect: true, // 構築時には接続せず、最初の呼び出しまで待機する
retryStrategy: (times) => {
if (times > 10) return null; // 10 回の再試行後に断念し、後で再接続する
return Math.min(times * 200, 5000); // 200ms、400ms、…、上限 5s
},
enableAutoPipelining: true, // 同時実行されるコマンドを 1 回の TCP 書き込みにまとめる
keepAlive: 10000, // 10s ごとに TCP keep-alive を実行する
});

主なトレードオフ:

  • maxRetriesPerRequest: null + retryStrategy — Redis の一時的な再起動によって すべてのリクエストが即座に失敗しないため、本番環境では推奨されます。 checkRateLimit() のインメモリフォールバックが障害経路を吸収します。
  • lazyConnect: true — サーバーが接続の受け付けを開始する前に Redis が起動している必要がなくなり、 起動時の依存関係を回避できます。
  • enableAutoPipelining: true — 同時実行されるレート制限チェックのラウンドトリップを削減します。 単一接続で 50 RPS を超える場合に効果的です。

2. Redis サーバー設定(redis.conf)

Section titled “2. Redis サーバー設定(redis.conf)”
# メモリ
maxmemory 80% # OS のページキャッシュ用の余裕を残す
maxmemory-policy allkeys-lru # メモリ逼迫時に古い認証キャッシュエントリを削除する
# 永続化(任意 — OmniRoute は永続化なしでもクラッシュに対して安全)
save 300 1 # 1 個以上のキーが変更された場合、少なくとも 5 分ごとにスナップショットを作成する
appendonly no # AOF は不要。データは再生成可能
appendfsync no # fsync のオーバーヘッドなし(RDB で十分)
# ネットワーク
timeout 0 # アイドル接続を切断しない
tcp-keepalive 300 # 5 分間隔の keep-alive
tcp-backlog 511 # バースト負荷に備えた接続バックログ
# パフォーマンス
hz 10 # デフォルト。レイテンシー重視の場合は 100
activedefrag yes # フラグメンテーションが 10% を超えた場合に自動デフラグする

maxmemory-policy allkeys-lru のトレードオフ: メモリ逼迫時には、認証キャッシュエントリが 削除される可能性があります。これは安全です。setCachedApiKey はキャッシュミス時に必ず再投入し、 SQLite フォールバックが信頼できる正本となります。レートリミッターの Lua スクリプトが作成するキーは小さく、 設計上、有効期間も短くなっています。

本番用 Compose(docker-compose.prod.yml)では redis:8.6.2-alpine を使用しています。以下を追加してください。

redis:
image: redis:8.6.2-alpine
command:
[
"redis-server",
"--maxmemory",
"512mb",
"--maxmemory-policy",
"allkeys-lru",
"--activedefrag",
"yes",
"--save",
"300 1",
]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s

4. マルチインスタンス / スケーリングに関する考慮事項

Section titled “4. マルチインスタンス / スケーリングに関する考慮事項”

すべてのレプリカで単一の Redis を使用 — レートリミッターの Lua スクリプトは、単一の 信頼できるキースペースに依存しています。各レプリカの背後で複数の Redis インスタンスを使用すると、 アトミック性が失われ、割り当て量が倍増します。すべてのアプリケーションレプリカで、単一の Redis (またはフェイルオーバー機能を備えた Redis Sentinel クラスター)を使用してください。

接続数: 各アプリケーションレプリカは、Redis への 2 本の TCP 接続 (レートリミッタークライアント + クォータストアクライアント)を開きます。10 レプリカでは 20 接続となり、 デフォルトの Redis インスタンスにおける 10k 接続の上限を十分に下回ります。

ヘルスチェックエンドポイント経由で公開します。

// src/app/api/monitoring/health/route.ts はすでに rateLimiter 関数を呼び出している
// Redis 固有のチェックを追加する:
// 1. ioredis の .ping() による PING レイテンシー
// 2. INFO memory によるメモリ使用量
// 3. INFO clients による接続数
// 4. maxmemory-policy のヒット率(evicted_keys / keyspace_hits)

監視すべき主なメトリクス:

  • 1 秒あたりの削除済みキー数 — ゼロ以外の状態が継続する場合は、maxmemory を増やす
  • ブロックされたクライアント数 — ゼロ以外の場合、Lua スクリプトが遅いか、競合が激しい可能性がある
  • 拒否された接続数 — 接続上限に到達していることを示す。20 接続ではまれ

flowchart LR
subgraph App["アプリのレプリカ"]
RL[rateLimiter.ts]
AK[apiKeys.ts]
QS[redisQuotaStore.ts]
end
RL -- "REDIS_URL" --> R1[(Redis\n共有)]
AK -- "RL のクライアントを再利用" --> R1
QS -- "QUOTA_STORE_REDIS_URL" --> R2[(Redis\nクォータストア)]
R1 --> R2 -- "同じインスタンスを使用可能" --> R1

ファイル 目的
src/shared/utils/rateLimiter.ts プライマリ Redis クライアント、Lua レート制限スクリプト、インメモリフォールバック
src/lib/db/apiKeys.ts 認証キャッシュ — Redis→SQLite フォールバック
src/lib/quota/redisQuotaStore.ts オプションのクォータストア用の独立した Redis クライアント
src/lib/quota/storeFactory.ts sqlite と redis のクォータドライバーを切り替える
docker-compose.prod.yml 本番環境用 Redis コンテナ(イメージ redis:8.6.2-alpine)
.env.example Redis 環境変数のドキュメント
src/app/api/local/redis/ 開発用コンテナのオーケストレーション向け API ルート
bin/cli/commands/redis.mjs 開発用コンテナのオーケストレーション向け CLI コマンド

OmniRoute ソースコード (a58000c7685f)

HagiCode

HagiCode は構造化ワークフロー、マルチエージェント実行、Hero Dungeon ビューを備えたエージェント型コーディングワークスペースです。

よりスマートで速く、楽しいエージェント型ワークフローで、使いやすいソフトウェアを形にします。

HagiCode ライトテーマのメイン画面
  • Smart構造化ワークフローは意図をアイデアから変更のリリースまで実行可能な道筋にします。
  • Efficientマルチエージェントのワークフローで調査、実装、レビューを並行して進めます。
  • FunHero Dungeon により長時間のコーディングを視覚的で協力的な体験にします。
HagiCode を見る