Rate Limit のストレージ選定:PostgreSQL vs Redis

重岡 正 ·  Mon, January 5, 2026

Giselle の API に Rate Limit を実装するにあたり、PostgreSQL と Redis のどちらを使用すべきか検討しました。

前回の記事 Rate Limit アルゴリズムの比較と事例調査 では Fixed Window Counter アルゴリズムを採用することを決めました。今回は、そのストレージ層として PostgreSQL を選択した理由をご紹介します。

Giselle での実装例

今回の PR feat(api/apps/run): add team-scoped rate limiting to App Run API · #2603 では、PostgreSQL を使用した Fixed Window Counter を実装しました。

PostgreSQL vs Redis Rate Limit の比較

観点PostgreSQLRedis
レイテンシ1-10ms0.1-1ms
スループット数千 req/s数十万 req/s
永続性デフォルトで永続設定次第(揮発可能)
運用コスト既存 DB を利用可能追加インフラが必要
原子性トランザクションシングルスレッド
スケール垂直スケール中心水平スケール容易

PostgreSQL を選ぶメリット

インフラの複雑さを回避

  • 既に PostgreSQL を使用中
  • Redis の追加運用・監視が不要
  • 障害点が増えない

データの一貫性

  • チーム・アプリとの外部キー制約
  • CASCADE DELETE で自動クリーンアップ
  • トランザクション分離

PostgreSQL のデメリット

レイテンシ

  • 各リクエストに +1-5ms の DB 往復
  • ただし Rate Limit を適用する API は既に DB 依存(認証、チーム取得など)

高負荷時のボトルネック

  • 数万 req/s では問題になる可能性
  • コネクションプール枯渇のリスク

テーブル肥大化

  • 古いウィンドウが蓄積
  • 定期的なクリーンアップが必要

このプロジェクトで PostgreSQL が適切な理由

1. 現在の Rate Limit 設定値

プラン制限換算
Pro300 req/min5 req/s
Team600 req/min10 req/s
Enterprise3000 req/min50 req/s

この規模であれば PostgreSQL で十分処理可能です。

2. 既存の API リクエストフロー

以下は概念的なサンプルコードです。

// 1 リクエストあたり既に複数の DB アクセスが発生
await authenticate()        // DB: API キー検証
await enforceRateLimit()    // DB: Rate Limit 適用 ← 今回追加
await loadApp()             // DB: アプリ情報取得
await executeTask()         // DB: タスク作成・実行

このように、1 クエリ追加の影響は相対的に小さいと言えます。

3. 運用の一貫性

  • 既存の監視・バックアップ体制を活用
  • 新しい依存関係の学習コストなし

Redis への移行を検討すべきタイミング

  • トラフィックが大幅に増加(数万 req/s)
  • レイテンシ要件が厳しくなった(<10ms 必須)
  • 複数リージョンでの分散が必要
  • より高度な Rate Limit が必要(Sliding Window 等)

まとめ

現時点では PostgreSQL で問題ないと判断しました。

  • プロジェクトの「シンプルさ優先」の哲学に合致
  • 現在の規模では性能的に十分
  • 将来的にボトルネックになった場合、Rate Limit チェック関数の実装を Redis に差し替えるだけで移行可能(インターフェースは変わらない)

必要になってから最適化する(YAGNI 原則)のが適切なアプローチだと考えています。

以上、Rate Limit のストレージ選定で PostgreSQL と Redis を比較検討した、現場からお送りしました。