constlimits=[{key:`rl:ip:${req.ip}`,limit: 100,windowSec: 60},// IP 기준
{key:`rl:user:${userId}`,limit: 1000,windowSec: 3600},// 사용자 시간당
{key:`rl:plan:${userId}`,limit: 50000,windowSec: 86400},// 일일
];for(constloflimits){if(!awaitslidingAllow(l.key,l.limit,l.windowSec))returnres.status(429).end();}
🤔 의사결정 기준
차원
키
Per-IP
rl:ip:${req.ip}
Per-user
rl:user:${userId}
Per-API key
rl:apikey:${key}
Per-endpoint
rl:endpoint:${path}:${userId}
비용 큰 작업 (PDF 생성)
per-user 더 엄격
알고리즘
권장
단순 / 정확성 보통
Fixed window
정확한 sliding 필요
Sliding window log (sorted set)
burst 허용 + 평균 통제
Token bucket
평탄한 처리 (DB 보호)
Leaky bucket
❌ 안티패턴
메모리 in-process counter: 다중 인스턴스에서 의미 없음. Redis 또는 외부.
X-Forwarded-For 검증 없이 IP 사용: 클라이언트가 위조 가능. 신뢰 가능한 proxy 만.
429 응답에 Retry-After 누락: 클라이언트가 언제 재시도할지 모름.
인증 endpoint 에 너무 헐거운 limit: brute force 무방비.
per-IP 만: NAT 뒤 다수 사용자 = 한 IP. user 기준 병행.
rate limit 자체에 타임아웃 누락: Redis 응답 늦으면 모든 요청 block.
fail-open vs fail-closed 결정 안 함: Redis 다운 시 다 통과 (fail-open) 또는 다 차단 (fail-closed). 명시.
🤖 LLM 활용 힌트
다층 limit (IP + user + plan) + Redis sorted set 권장.