Notre avis
Ce guide fournit des instructions pour concevoir et implémenter une limitation de débit (rate limiting) à l'aide de divers algorithmes, avec des exemples en Node.js et Redis.
Points forts
- Couvre plusieurs algorithmes avec des diagrammes clairs
- Inclut des implémentations concrètes (script Lua, middleware Node.js)
- Propose des stratégies par niveau et dynamiques
Limites
- Suppose Redis comme seul stockage
- Ne traite pas la coordination distribuée
- Exemples limités à Node.js
À utiliser lors de la conception d'une limitation de débit pour une API web, notamment avec Redis et Node.js.
À éviter si la solution doit être indépendante du langage ou sans Redis, ou pour des limitations de débit simples en mémoire.
Analyse de sécurité
SûrThe skill provides educational content and code examples for rate limiting design. It does not include any destructive commands, data exfiltration, or execution of external scripts. The code snippets are for illustration only and do not pose a risk.
Aucun point d'attention détecté
Exemples
Implement a token bucket rate limiter using Redis Lua script for my Express API.Set up tiered rate limiting for free, basic, and pro users in my Node.js app.Implement a sliding window counter rate limiter with Redis and Node.js.name: "rate-limit" description: "레이트 리밋 설계 가이드를 실행합니다." user-invocable: true
Rate Limiting Skill
레이트 리밋 설계 가이드를 실행합니다.
레이트 리밋 알고리즘
Token Bucket
버킷에 토큰이 일정 속도로 추가
요청 시 토큰 소비
토큰 없으면 거부
┌─────────────┐
│ ○ ○ ○ ○ ○ │ ← 토큰 추가 (초당 10개)
│ Bucket │
└──────┬──────┘
↓ 요청당 1토큰 소비
[Request]
장점: 버스트 허용, 평균 속도 제한
구현: Redis + Lua Script
Leaky Bucket
요청이 버킷에 쌓임
일정 속도로 처리
버킷 넘치면 거부
[Request]
↓
┌─────────────┐
│ ░ ░ ░ ░ ░ │ ← 큐 (고정 크기)
└──────┬──────┘
↓ 일정 속도로 처리
[Processed]
장점: 일정한 출력 속도
단점: 버스트 불가
Fixed Window
고정 시간 창에서 요청 수 제한
|----60초----|----60초----|
| 100 요청 | 100 요청 |
|____________|____________|
단점: 경계에서 2배 버스트 가능
(59초에 100개 + 61초에 100개)
Sliding Window Log
각 요청의 타임스탬프 기록
윈도우 내 요청 수 계산
현재 시간: 10:05:30
윈도우: 60초
[10:04:31, 10:04:45, 10:05:10, 10:05:25]
→ 윈도우 내 4개 요청
장점: 정확함
단점: 메모리 사용 많음
Sliding Window Counter
이전 윈도우와 현재 윈도우 가중 평균
이전 윈도우 (70개) × 30% + 현재 윈도우 (50개) × 70%
= 21 + 35 = 56개
장점: 메모리 효율적, 상당히 정확
구현 예시
Redis + Token Bucket
-- rate_limit.lua
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local bucket = redis.call('HMGET', key, 'tokens', 'last_update')
local tokens = tonumber(bucket[1]) or limit
local last_update = tonumber(bucket[2]) or now
-- 토큰 리필
local elapsed = now - last_update
local refill = elapsed * (limit / window)
tokens = math.min(limit, tokens + refill)
if tokens >= 1 then
tokens = tokens - 1
redis.call('HMSET', key, 'tokens', tokens, 'last_update', now)
redis.call('EXPIRE', key, window)
return {1, tokens} -- 허용, 남은 토큰
else
return {0, 0} -- 거부
end
Node.js 미들웨어
const Redis = require('ioredis');
const redis = new Redis();
const rateLimitScript = fs.readFileSync('rate_limit.lua', 'utf8');
async function rateLimit(options) {
const { key, limit, window } = options;
return async (req, res, next) => {
const identifier = req.ip; // 또는 req.user.id
const redisKey = `ratelimit:${key}:${identifier}`;
const [allowed, remaining] = await redis.eval(
rateLimitScript,
1,
redisKey,
limit,
window,
Date.now() / 1000
);
res.set('X-RateLimit-Limit', limit);
res.set('X-RateLimit-Remaining', remaining);
if (!allowed) {
res.set('Retry-After', window);
return res.status(429).json({
error: 'Too Many Requests',
retryAfter: window,
});
}
next();
};
}
// 사용
app.use('/api/', rateLimit({ key: 'api', limit: 100, window: 60 }));
app.use('/api/search', rateLimit({ key: 'search', limit: 10, window: 60 }));
Express Rate Limit
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const limiter = rateLimit({
store: new RedisStore({
client: redis,
prefix: 'rl:',
}),
windowMs: 60 * 1000, // 1분
max: 100, // 100 요청
message: { error: 'Too many requests' },
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
레이트 리밋 전략
계층별 제한
const limits = {
global: { limit: 10000, window: 60 }, // 전체 API
authenticated: { limit: 1000, window: 60 }, // 인증된 사용자
anonymous: { limit: 100, window: 60 }, // 익명 사용자
endpoint: { // 엔드포인트별
'/api/search': { limit: 10, window: 60 },
'/api/upload': { limit: 5, window: 60 },
},
};
사용자 티어별
const tierLimits = {
free: { limit: 100, window: 3600 }, // 시간당 100
basic: { limit: 1000, window: 3600 }, // 시간당 1000
pro: { limit: 10000, window: 3600 }, // 시간당 10000
enterprise: { limit: 100000, window: 3600 },
};
function getRateLimit(user) {
return tierLimits[user.tier] || tierLimits.free;
}
동적 제한
// 부하에 따른 동적 조정
async function getDynamicLimit() {
const load = await getSystemLoad();
if (load > 0.9) return { limit: 50, window: 60 }; // 높은 부하
if (load > 0.7) return { limit: 75, window: 60 }; // 중간 부하
return { limit: 100, window: 60 }; // 정상
}
응답 헤더
표준 헤더
X-RateLimit-Limit: 100 # 최대 요청 수
X-RateLimit-Remaining: 45 # 남은 요청 수
X-RateLimit-Reset: 1640000000 # 리셋 시간 (Unix timestamp)
Retry-After: 30 # 재시도까지 초 (429 응답 시)
응답 예시
// 429 Too Many Requests
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Try again in 30 seconds.",
"retryAfter": 30,
"limit": 100,
"remaining": 0,
"reset": 1640000000
}
}
분산 환경
Redis Cluster
// 모든 인스턴스가 같은 Redis 참조
const redis = new Redis.Cluster([
{ host: 'redis-1', port: 6379 },
{ host: 'redis-2', port: 6379 },
{ host: 'redis-3', port: 6379 },
]);
일관성 고려
Strong Consistency: 모든 노드가 동일한 카운트 (느림)
Eventual Consistency: 일시적 불일치 허용 (빠름)
대부분의 레이트 리밋은 Eventual Consistency로 충분
약간의 초과 허용이 성능보다 덜 중요
체크리스트
설계
- [ ] 알고리즘 선택
- [ ] 제한 수치 결정
- [ ] 키 식별자 정의 (IP, 사용자, API 키)
- [ ] 티어별 제한 설계
구현
- [ ] 분산 저장소 (Redis)
- [ ] 응답 헤더 설정
- [ ] 에러 응답 형식
- [ ] 바이패스 규칙 (내부, 헬스체크)
운영
- [ ] 모니터링/알림
- [ ] 제한 초과 로깅
- [ ] 동적 조정 메커니즘
출력 형식
## Rate Limit Design
### Strategy
- 알고리즘: Token Bucket
- 저장소: Redis
### Limits
| 대상 | 제한 | 윈도우 | 키 |
|------|------|--------|-----|
| Global | 10000 | 분 | IP |
| Auth User | 1000 | 분 | user_id |
| Search API | 10 | 분 | user_id |
### Implementation
```javascript
// 핵심 구현 코드
Response Format
// 429 응답 예시
---
요청에 맞는 레이트 리밋 전략을 설계하세요.
Expert Next.js App Router
Developpement
Un skill qui transforme Claude en expert Next.js App Router.
Générateur de README
Developpement
Crée des README.md professionnels et complets pour vos projets.
Rédacteur de Documentation API
Developpement
Génère de la documentation API complète au format OpenAPI/Swagger.