Rate Limit Storage Selection: PostgreSQL vs Redis
When implementing rate limiting for the Giselle API, we considered whether to use PostgreSQL or Redis.
In the previous article Rate Limit Algorithm Comparison and Case Studies, we decided to adopt the Fixed Window Counter algorithm. This time, we’ll explain why we chose PostgreSQL as the storage layer.
In this PR feat(api/apps/run): add team-scoped rate limiting to App Run API · #2603, we implemented Fixed Window Counter using PostgreSQL.
| Aspect | PostgreSQL | Redis |
|---|---|---|
| Latency | 1-10ms | 0.1-1ms |
| Throughput | Thousands req/s | Hundreds of thousands req/s |
| Persistence | Persistent by default | Configurable (can be volatile) |
| Operational cost | Can use existing DB | Additional infrastructure needed |
| Atomicity | Transactions | Single-threaded |
| Scaling | Primarily vertical | Easy horizontal scaling |
| Plan | Limit | Equivalent |
|---|---|---|
| Pro | 300 req/min | 5 req/s |
| Team | 600 req/min | 10 req/s |
| Enterprise | 3000 req/min | 50 req/s |
At this scale, PostgreSQL can handle it sufficiently.
Below is a conceptual sample code.
// Multiple DB accesses already occur per request
await authenticate() // DB: API key verification
await enforceRateLimit() // DB: Rate limit enforcement ← Added this time
await loadApp() // DB: Load app information
await executeTask() // DB: Create and execute taskAs shown, the impact of adding one query is relatively small.
We determined that PostgreSQL is fine for now.
We believe optimizing only when needed (YAGNI principle) is the appropriate approach.
That’s all from the Gemba on comparing PostgreSQL and Redis for rate limit storage selection.