Concurrency limit: giới hạn số tác vụ đắt tiền chạy cùng lúc.
Load shedding: chủ động loại bớt công việc khi hệ thống quá tải.
Bình luận
Một API khỏe thường kết hợp nhiều lớp thay vì chỉ một counter.
Threat model trước khi chọn con số
Rate limiter phải trả lời bốn câu hỏi:
Đang bảo vệ tài nguyên nào? Login, OTP, password reset, search, export, upload và AI inference có chi phí rất khác nhau.
Ai đang tiêu thụ? IP, account, API key, user, tenant, device, session hay subnet?
Giới hạn điều gì? Request count, weighted cost, bytes, CPU estimate, concurrent jobs hay failure count?
Khi vượt ngưỡng thì làm gì? Reject, delay, queue, CAPTCHA, step-up MFA, temporary cooldown hay block ở edge?
Nếu chỉ giới hạn theo IP, hàng nghìn attacker IP có thể password-spray một account. Nếu chỉ giới hạn theo account, attacker có thể cố tình khóa tài khoản của nạn nhân. Vì vậy authentication endpoints cần nhiều dimension và phản ứng tăng dần.
Kiến trúc nhiều lớp
Mermaid
Loading diagram…
Edge/CDN: hấp thụ traffic trước khi tới origin, chặn bot/signature và giới hạn theo network context.
API gateway: áp quota chung theo route, API key, tenant hoặc service plan.
Application: hiểu account, operation cost và business context.
Downstream controls: connection pool, queue length, timeout, circuit breaker, DB statement timeout.
Redis phù hợp cho distributed limiter vì nhiều app instances dùng chung state, có TTL tự dọn và hỗ trợ atomic Lua/function execution.
Chọn thuật toán
Không có thuật toán “an toàn nhất” cho mọi endpoint. Login failure counter và public read API không nhất thiết dùng cùng policy.
Fixed window bằng Redis: lỗi race phổ biến
Cách ngây thơ:
Nếu process chết giữa INCR và EXPIRE, key có thể tồn tại lâu hơn dự kiến. Check rồi increment bằng nhiều round trip cũng có race khi nhiều instances chạy đồng thời.
Gói logic vào Lua để atomic:
Node.js gọi script:
Lua chạy atomically trên Redis, nhưng script phải ngắn và bounded; script dài sẽ block event loop Redis.
Token bucket cho burst có kiểm soát
Token bucket giữ:
tokens: số token còn lại.
lastRefill: thời điểm refill gần nhất.
capacity: burst tối đa.
refillRate: token thêm mỗi giây.
cost: chi phí request hiện tại.
Pseudo-code:
Toàn bộ read–refill–consume–write phải nằm trong một Lua script hoặc Redis Function. Dùng time nhất quán; không tin timestamp do client gửi. Đặt TTL đủ để bucket không hoạt động tự dọn.
Weighted cost hữu ích hơn request count thuần:
Tuy nhiên, cost là estimate; vẫn cần concurrency limits và timeout cho tác vụ đắt tiền.
Thiết kế key đúng
Key phải namespace và version rõ ràng:
Các dimension thường dùng:
Anonymous: IP hoặc privacy-preserving hash của IP prefix.
Authenticated: user/API key + tenant.
Login: account identifier và IP/device/network.
OTP/reset: destination/account + IP + global campaign detector.
Không ghép raw email, phone hoặc bearer token vào Redis key/log. Chuẩn hóa identifier trước khi HMAC/hash để tránh bypass bằng hoa/thường, Unicode hoặc whitespace.
Với Redis Cluster, Lua nhiều key phải cùng hash slot. Dùng hash tags có chủ đích, nhưng đừng dồn toàn bộ traffic vào một slot nóng. Nếu policy cần nhiều dimension ở nhiều slot, cân nhắc thực thi các limiter độc lập rồi deny nếu bất kỳ limiter nào vượt ngưỡng.
Bảo vệ login khỏi brute-force
Một policy hiệu quả thường gồm:
Layer 1: per-IP/network
Giới hạn tốc độ từ một nguồn, nhưng không xem đây là identity duy nhất. NAT có thể làm nhiều user hợp lệ dùng chung IP; botnet có thể phân tán qua nhiều IP.
Layer 2: per-account
Theo dõi failure count trên account đã chuẩn hóa. Dùng delay/cooldown tăng dần thay vì permanent lockout dễ bị lợi dụng để DoS nạn nhân.
Ngưỡng chỉ là ví dụ; cần tuning theo sản phẩm và telemetry.
Layer 3: cross-account detection
Phát hiện một IP/device thử ít password trên nhiều account—password spraying hoặc credential stuffing. Per-account limit đơn lẻ không bắt được mẫu này.
Layer 4: defenses không dựa vào rate
MFA/passkeys.
Password breach checks.
Device/risk signals.
Generic error và timing để giảm account enumeration.
Alert cho user và security team.
Bot management/CAPTCHA có chọn lọc.
Rate limiting làm cuộc tấn công chậm và đắt hơn; không chứng minh request là hợp lệ.
OTP, password reset và resend
Các endpoint này phải có policy riêng:
Giới hạn request gửi OTP theo account/destination/IP.
Giới hạn verify failures theo challenge, account và network.
Token/challenge hết hạn và one-time use.
Cooldown giữa các lần resend.
Global spend cap để chống SMS/email cost abuse.
Không reset failure counter chỉ vì attacker xin code mới.
Thành công có thể giảm một số counter, nhưng không nên xóa toàn bộ risk history ngay lập tức.
DDoS tầng ứng dụng: Redis giúp gì và không giúp gì?
Layer 7 DDoS nhắm vào HTTP operations hợp lệ nhưng đắt: search, GraphQL, report, image transform, login, cache miss hoặc database fan-out.
Redis limiter ở application có thể:
Chặn per-user/API-key/tenant abuse chính xác.
Giới hạn weighted cost và concurrency.
Bảo vệ downstream trước khi chạy truy vấn đắt.
Chia sẻ state giữa nhiều app instances.
Kích hoạt challenge, degraded mode hoặc load shedding.
Nhưng Redis ở origin không thể tự chống volumetric DDoS:
Traffic đã tiêu tốn bandwidth, TLS và connection resources trước khi middleware chạy.
Redis có thể trở thành bottleneck mới.
Attacker phân tán cardinality cao có thể tạo hàng triệu key.
Nếu mọi request đều chạm origin, chi phí vẫn lớn.
Vì vậy, đặt coarse limiter tại CDN/WAF/gateway; application limiter xử lý identity và business cost; infrastructure controls bảo vệ network và capacity.
Cardinality attack và memory safety
Attacker có thể tạo vô số IP, username hoặc path để ép Redis sinh key. Phòng vệ:
Chỉ dùng route template, không dùng raw URL/path/query làm key.
TTL cho mọi ephemeral key.
Giới hạn độ dài và normalize subject.
Theo dõi key creation rate và memory.
Dùng approximate/global guard cho anonymous high-cardinality traffic.
Không lưu một sorted-set member cho mỗi request nếu throughput quá lớn.
Đặt maxmemory và eviction policy có chủ đích; eviction limiter keys có thể fail open ngoài ý muốn.
Response chuẩn khi bị giới hạn
Trả:
HTTP 429 Too Many Requests cho client-specific limit.
Retry-After khi có thể tính thời điểm retry.
Rate-limit headers theo convention/standard mà hệ sinh thái của bạn hỗ trợ.
Body ổn định với machine-readable error code.
Không tiết lộ chính xác anti-abuse state trên login nếu thông tin đó giúp attacker tối ưu chiến thuật. Với server overload toàn cục, 503 Service Unavailable có thể phù hợp hơn 429.
Client phải dùng exponential backoff + jitter và tôn trọng Retry-After; retry tức thì chỉ làm overload nặng hơn.
Fail-open hay fail-closed khi Redis lỗi?
Đây là quyết định theo endpoint:
Login, OTP, payment: thường ưu tiên fail closed hoặc local emergency limit.
Public read ít rủi ro: có thể fail open với in-process fallback để giữ availability.
Tác vụ cực đắt: load shed nếu không xác minh được quota.
Không để timeout Redis bằng timeout request. Dùng timeout rất ngắn, connection pool, circuit breaker và metrics. In-memory fallback chỉ bảo vệ từng instance, không có global consistency.
Multi-region và consistency
Global counter đồng bộ tuyệt đối có thể tăng latency và giảm availability. Các lựa chọn:
Limit theo region và dành safety margin.
Phân bổ quota cho từng region.
Edge limiter cho coarse control, central Redis cho account/security events.
Chấp nhận bounded overshoot và đo mức tối đa.
Route một subject về home region cho strict policy.
Ghi rõ semantics: “100/phút toàn cầu” khác “100/phút/region”.
Observability và tuning
Theo dõi:
Allowed/denied/delayed theo policy và route.
Redis latency, errors, script duration và hot keys.
429 ratio, retry behavior và false-positive complaints.
Cardinality, memory, eviction và key creation rate.
Login failures theo account/IP/device và distributed patterns.
Shadow mode trước khi enforce giúp ước lượng impact. Phân biệt security limit, commercial quota và overload protection trong metrics.
Proxy và IP an toàn
Chỉ tin X-Forwarded-For/Forwarded từ proxy nằm trong trusted network. Nếu app trực tiếp tin header do internet client gửi, attacker có thể đổi IP ở mỗi request để bypass.
Chuẩn hóa IPv4/IPv6, xử lý trusted proxy chain và quyết định prefix strategy. IP là signal dễ thay đổi, không phải định danh user hoàn hảo.
Testing
Unit test ranh giới window, refill, TTL và weighted cost.
Concurrency test để chứng minh không oversell token.
Test process crash và Redis reconnect.
Test clock skew và timestamp precision.
Load test hot key và hàng triệu subjects.
Chaos test Redis timeout, failover và eviction.
Security test spoofed proxy headers, username variants, distributed spray và CAPTCHA bypass.
Verify request bị deny trước DB query, password hash hoặc downstream call đắt tiền nếu có thể.
Checklist production
Policy được thiết kế theo endpoint cost và threat model.
Có limiter theo nhiều dimension, không chỉ IP.
Redis update atomic bằng Lua/Function hoặc primitive phù hợp.
Mọi limiter key có TTL và namespace/version.
Identifier được normalize và không lộ PII/token.
Login có per-account, per-source và cross-account detection.
OTP/reset có send, verify, resend và spend limits riêng.
Layer 7 protection có edge/WAF/gateway trước origin.
429, Retry-After, backoff và error body nhất quán.
Fail-open/closed được định nghĩa cho từng route.
Redis memory, eviction, cardinality, hot keys và latency được giám sát.
Trusted proxy/IP parsing đã được kiểm thử.
Có shadow mode, tuning và incident override/runbook.
Kết luận
Redis là nền tảng mạnh cho distributed rate limiting, không phải lá chắn DDoS độc lập. Giá trị thật đến từ thiết kế policy: identity nhiều chiều, thuật toán phù hợp, update atomic, TTL, weighted cost và phản ứng tăng dần.
Dùng edge để hấp thụ traffic lớn; gateway để kiểm soát quota thô; application + Redis để hiểu account và business cost; downstream limits để bảo vệ tài nguyên cuối. Khi các lớp phối hợp, rate limiting mới vừa giảm brute-force và API abuse, vừa tránh biến chính limiter thành điểm lỗi mới.
Mục lục(23)
Codelua
1local current = redis.call('INCR', KEYS[1])2if current == 1 then3 redis.call('EXPIRE', KEYS[1], ARGV[1])4end5local ttl = redis.call('TTL', KEYS[1])6return {current, ttl}
Hướng dẫn xử lý transaction storm trong flash sale và quyết toán lương với RabbitMQ/Kafka, rate limiting, backpressure, circuit breaker, load shedding, idempotency và capacity planning.
So sánh bốn thuật toán Rate Limiting cho API: Token Bucket, Leaky Bucket, Fixed Window và Sliding Window Log; cách triển khai Redis atomic, trả HTTP 429 và chống bot phân tán.