Conception de rate limiter's
1) Pourquoi le rate limiting
Le rate limiting protège la disponibilité et l'économie de l'API : arrête les fluds, les « burst » des retraits, le credential stuffing, protège les transactions coûteuses (transactions monétaires, génération de rapports), lisse la charge sur les systèmes dépendants (OBD/fournisseurs). Un bon design donne justice (fairness), latence prévisible et SLO clair.
Objectifs clés
Stabilité RPS et protection du backend contre la surcharge.
« élasticité » contrôlée (burst allowance).
Différenciation des clients (per-user/per-organization/per-key/per-IP/per-region).
Modèle de valeur : différents « prix » pour différentes opérations.
2) Types de limites
Limites RPS : requêtes par seconde/minute.
Quotas : budget total par période (jour/mois).
Compétitivité : opérations simultanées (checkout, heavy job).
Vitesse/bande : octet/seconde (chargement/déchargement).
Limites pondérées : « coût » de la requête en fonction de la complexité (par exemple, la complexité GraphQL, taille batch).
Adaptative : se durcit en cas d'anomalies (activité suspecte/erreurs 401/403/5xx).
3) Algorithmes et quand les appliquer
3. 1 Fixed window counter
Simple : compteur par intervalle (par exemple 100 r/min).
Avantages : coût minimum. Inconvénients : « bâtonnets de bord » aux limites de la fenêtre.
Quand : panneaux d'amiral, faible précision, faible coût.
3. 2 Sliding window (log / counter)
Log : stocke les horodatages des dernières requêtes, précis, routes de la mémoire.
Contre : moyenne de deux fenêtres adjacentes (rolling), compromis de précision et de prix.
Quand : API publiques du trafic moyen, vous avez besoin de fluidité sans mathématiques complexes.
3. 3 Token bucket
Paramètres : vitesse « r » (tokens/secondes) et capacité « b » (burst). Chaque requête « brûle » un jeton.
Avantages : burst allowance naturelle, réalisation simple. Inconvénients : il n'y a pas d'uniformité stricte.
Quand : presque toujours pour RPS si vous avez besoin de « salves » à l'intérieur de « b ».
3. 4 Leaky bucket (drip)
File d'attente à partir de laquelle « fuit » à vitesse fixe.
Avantages : flux de sortie régulier. Inconvénients : plus de retards.
Quand : lisser vers des fournisseurs externes « fragiles ».
3. 5 GCRA (Generalized Cell Rate Algorithm)
Modèle d'heure d'arrivée théorique (TAT) :- « TAT _ next = max (TAT_current, maintenant) + 1/r », la requête est acceptée si « now <= TAT_current + burst/r ».
- Avantages : rigoureux, précis, peu de mémoire (nous stockons TAT par clé). Inconvénients : plus difficile à comprendre.
Quand : besoin de contrôle strict et de fluidité, limites distribuées.
3. 6 Sémaphores compétitifs
Un compteur d'opérations actives ; entrée - s'il y a des « billets » ; la sortie est la libération.
Quand : opérations de long-running, threads, WebSocket, téléchargements.
4) Modèle de clé limite
Clé = combinaison d'attributs :- `client_id`/`api_key`/`user_id`/`org_id`
- « IP/ASN/geo » (défense grossière)
- 'endpoint/method '(itinéraires chauds)
- 'Scope/plan/tier '(monétisation)
- 'idempotency _ key '(write-operations)
- Utilisez une hiérarchie : d'abord une clé per stricte, puis une organisation per, puis une organisation globale.
5) Poids de la demande (modèle cost)
Définissez le « coût » de 'cost (q)' :- GraphQL : complexité par champs × profondeur.
- REST : taille de la réponse/requête, type d'opération (read = 1, write = 3, rapport = 10).
- Batch: `cost = min(n, cap)`.
- On limite les tokens et non les « requêtes » : 'budget - = cost (q)'.
6) Réalisation distribuée
6. 1 Entrepôts
In-process : ultra-rapide, mais pas la limite générale (utile pour les limites « douces » locales).
Redis : standard de facto. INCR/EXPIRE, scripts Lua (atomicité), ZSET pour sliding window, clés avec TTL.
Envoy/NGINX/Kong/Traefik : filtres intégrés ; pratique pour le périmètre.
Service Mesh : limites locales sur sidecar + synchronisation globale.
6. 2 Atomicité et course
Lua dans Redis : vérification et incrémentation en une seule étape.
GCRA : Stocker un TAT avec CAS/script.
Cohérence horlogère : NTP, minuteries monotones.
Sharding : hash cohérent par clé ; évitez les chardes « chaudes ».
6. 3 Géo-distribution
Limites locales sur les clusters régionaux + global supérieur (coarse).
CRDT/réplication - attention (retards, double débit). Il est préférable de fixer des limites régionales pour les stocks.
7) Politiques et priorités
Plans : Free/Pro/Enterprise avec différents « r », « b », quotas.
Priorités : les itinéraires « chers » reçoivent une limite plus faible ou plus élevée.
Listes : allow-list pour les intégrations, deny par ASN/proxy/TOR.
Escalade : en cas de dépassement répété - abaissons la limite, entrez proof-of-work/captcha/challenges.
8) Exemples de configues
8. 1 Envoy (HTTP rate limit filter, pseudo)
yaml rate_limit:
domain: public-api descriptors:
- key: api_key rate_limit:
unit: second requests_per_unit: 50 burst: 100
- key: api_key value: payments. write rate_limit:
unit: second requests_per_unit: 5 burst: 10
8. 2 NGINX (lua + Redis, pseudo)
nginx lua_shared_dict limits 10m;
location /api/ {
access_by_lua_block {
local key = ngx. var. arg_apikey.. ":".. ngx. var. request_method.. ":".. ngx. var. uri
-- token bucket in Redis (evalsha)
local allowed, retry_after = ratelimit_allow(key, 50, 100) -- r=50/s, b=100 if not allowed then ngx. header["Retry-After"] = retry_after return ngx. exit(429)
end
}
proxy_pass http://backend;
}
8. 3 Limites de concurrence (pseudo-code)
pseudo on_request_start(key):
if redis. incr_with_ttl("sem:" + key, ttl=60) > MAX_CONCURRENCY:
redis. decr("sem:" + key); reject(429)
on_request_finish(key):
redis. decr("sem:" + key)
8. 4 GCRA (pseudo-code)
pseudo params: r tokens/sec, burst b tat = redis. get(key) or now allowed_time = tat - (b / r)
if now < allowed_time: reject(429, retry_after = allowed_time - now)
tat_next = max(tat, now) + 1/r redis. set(key, tat_next, ttl = ceil(b/r) + safety)
9) Intégration avec les retraits, les timaoutes et le circuit breaker
Retry-budget : limitez la proportion de retraits à X % du trafic principal.
Jitter : avec backoff, ajoutez toujours un jitter - réduit les surtensions synchrones.
Circuit breaker : en cas d'erreur élevée ('5xx', timeouts), abaissez les limites ou transférez une partie des itinéraires en « read-only ».
Hedging : soigneusement ; tenir compte du cost pour ne pas doubler la dépense budgétaire.
10) Observation et gestion
Метрики: `rps_allowed`, `rps_blocked`, `429_rate`, `retry_after_avg`, `burst_used`, `quota_remaining`, `active_concurrency`.
Labels : par la clé de la limite, la région, l'endpoint, le plan.
Logs de solution (samplés) : cause de défaillance, compteurs actuels, clé TTL.
Dashboards : cartes thermiques par clés/endpoints, clients « chauds ».
Alert : croissance de 429> 2 à 5 % sur les itinéraires critiques, « épuisement » fréquent des quotas, déséquilibre des chardes.
11) Tests et validation
Tests contractuels de stratégies (tableaux « si »).
Charge : bourrelets (x10 de r), longs plateaux, modèles « sales » (slow-POST, longs joints).
Trafic chaos : flux inégaux, clock drift, chute Redis/mesh.
A/B-inclusion : canary rollout limites, shadow solutions (logons, mais ne bloquons pas) avant d'allumer.
12) Mallettes et subtilités
Clock skew : utilisez 'now ()' à partir d'une source unique (serveur) et non des en-têtes du client.
Idempotency-Key : pour write - réduit l'amplification lors des retraits.
Opérations de batch : limitez la taille du batch et le cost total.
Long-bou/WebSocket : limitez le nombre de canaux/abonnements et la durée.
Cold start : Démarrage « chaud » des compteurs/pré-démarrage ; sinon, des surtensions de faux 429.
Demandes de calcul coûteuses : limitez-les à la logique d'entreprise.
Limites TTL : Les clés TTL doivent couvrir la fenêtre + stock (marge de sécurité).
13) Escalade antibot
Étapes : avertissement → 429 + 'Retry-After' → chalenge (captcha/puzzle) → bloc temporaire.
Signaux : device-fingerprint, comportement du curseur/temporisation, TOR/proxy/hébergement.
Les politiques doivent être déterministes et reproductibles pour les forensistes.
14) Sécurité et conformité
Deny-by-default sur des itinéraires critiques (write/finance).
Vérification : conservez les solutions de limitation pour les cas réglementaires et l'analyse des incidents.
PII : les clés limites ne doivent pas révéler de données personnelles dans les logs.
15) Chèque-liste prod-prêt
- Les clés limites et le modèle cost sont définis.
- L'algorithme (token bucket/GCRA) et le stockage (Redis/passerelle) ont été sélectionnés.
- Politiques pour tier's clients + « fusibles » mondiaux.
- Limites concurrentielles pour les opérations longues.
- Retry-budget, backoff avec jitter, intégration avec circuit breaker.
- Dashboards/alertes, logs samplés de solutions.
- Canary-activation et shadow-mode.
- Tests de burst, plateaux longs, pannes Redis, skew de clock.
- Documentation client : codes 429, 'Retry-After', exemples de backoff exponentiel.
16) TL; DR
Utilisez token bucket ou GCRA avec Redis/passerelle, concevez les clés limites et la valeur des requêtes, ajoutez des sémaphores compétitifs pour les opérations longues, intégrez-les avec le budget retry et circuit breaker, observez le 429 et la « capacité burst », étendez les limites via canary/shadow et assurez-vous tester les boursouflures et les défaillances de stockage.