Architecture à faible latence
Pourquoi une architecture à faible latence est-elle nécessaire ?
Une faible latence n'est pas seulement une « moyenne rapide », mais des queues stables (p95/p99) à charge réelle. Il s'agit du budget de retard, de la discipline des files d'attente/retraits, de la proximité des données et des caches, des protocoles/connexions corrects et de l'exploitation stricte (limites, observabilité, dégradation).
Objectifs et budget de retard
1. Définissez SLO : "p95 ≤ 120 ms, p99 ≤ 250 ms, erreur ≤ 0. 3%».
2. Collectez le budget : client → edge → la région → les services → stores → la réponse.
- Client-edge : 15 ms
- Région Edge : 15 ms
- Gateway/L7 : 10 ms
- Service aux entreprises : 40 ms
- Stockage/cache : 25 ms
- Stock/Gitter : 15 ms
Métriques et queues
Merit p50/p90/p95/p99, à travers et sur chaque hop.
Décomposez par label : région, méthode, version client, type de réseau (mobile/broadband), taille payload.
Différenciez l'heure de la file d'attente et l'heure d'exécution (voir Little's Law : L = λ· W).
Techniques sensibles au tail : requests en cascade (rarement et avec protection), interdiction des retraits en cascade.
Réseau et protocoles
QUIC/HTTP/3 : moins de pertes sur mobile/itinérance, multiplexage sans head-of-line.
TLS 1. 3 et 0-RTT (uniquement pour les demandes idempotentes sécurisées).
DNS : court TTL pour les itinéraires dynamiques, Anycast pour POP.
TCP : 'TCP _ NODELAY' (prudent), désactiver le superflu 'Nagle '/' Delayed ACK' là où il est justifié ; keep-alive et récupération rapide des connexions.
gRPC/HTTP/2 : multiplex, flow-control et réglages des fenêtres ; éviter la compression excessive sur les petits payload.
Connexions et pools
Séparez les pools par domaine/destination (afin que les « voisins lents » ne prennent pas les slots).
Warm-up/Keep-alive : maintenir un nombre soutenu de connexions chaudes.
Connection coalescing (HTTP/2/3) и reuse.
Temporisation : 'connect', 'TLS handshake', 'request', 'idle'. Différentes valeurs sur différents hops.
Localisation des données et calculs
Edge/région : faites des lectures et des calculs faciles plus proches de l'utilisateur (voir « Edge nœuds et logique régionale »).
Read-local/Write-global : répliques en lecture, vérité globale en écriture.
Hiérarchie cache : Cache CDN/edge → KV/Redis régional → cache de service → in-proc local.
Échauffement (warming) : chargement des clés chaudes lors de la sortie/mise à l'échelle.
Stale-while-revalidate pour les données à faible risque.
Entrepôts et index
Sélectionner les circuits dʼaccès O (1 )/O (logN) ; gardez les indices étroits à des demandes fréquentes.
Hot-keys : Chardonnez par 'hash (id)' ou ajoutez « sel » pour l'uniformité.
Batching à la sortie de la base de données/cache (jusqu'à des tailles raisonnables) au lieu de dizaines d'appels uniques.
Pour OLTP - transactions aussi courtes que possible ; read-committed/snapshot au lieu de serrures en série.
Concurrence et techniques sans blocage
Tout d'abord, éliminez les attentes sur les files d'attente, puis optimisez votre CPU.
Async I/O et les pilotes non bloquants ; structures de lock-free le cas échéant.
Évitez les mutex mondiaux ; granular-loki, CAS/versioning.
Pools de flux : fixez les dimensions pour ne pas s'appuyer sur des pulls contextuels.
NUMA-conscientisation : liaison des flux aux sockets, allocateurs locaux.
JVM/GC et rantim tuning (le cas échéant)
Génération de code et allocations : moins d'effets latéraux → moins de pauses GC.
Collecteurs modernes (G1/ZGC/Shenandoah) avec pauses cibles ; escapes et location de tampons.
Class/Data sharing, JIT warming, AOT/native-image pour les fonctions dépendantes de démarrage.
Incluez les histogrammes des pauses GC dans le budget total des retards.
Files d'attente, backpressure, protection contre les surcharges
Taille des files d'attente = petite : les longues files donnent « belle p50 » et tuent p99.
Backpressure explicite : répondez « plus lentement » que de creuser.
Concurrence adaptative : Abaissez la parallèle lorsque les erreurs/latences augmentent (algorithmes VEGAS/gradient, AIMD).
Circuit breaker : défaillances rapides lors de la dégradation de l'aptrim, bulkhead (cabines) sur les bassins et les ressources.
Rate limit : fenêtre glissante/tokens, hiérarchisation (user tier/critical-path).
Retraite, couverture et idempotence
Retrai seulement sur les erreurs de transit, avec un gitter et un maximum de tentatives.
Les opérations idempotentes et 'Idempotency-Key' sont obligatoires pour les répétitions.
Hedged requests : envoyer les prises après le seuil (p. ex. p95 + 10 ms) et toujours annuler l'excédent.
Ne jamais reculer à l'intérieur de chaque couche sans coordination - obtenir une tempête.
Mise en cache et échauffement
La voie chaude doit être sans réseau avec une charge type (in-proc/LRU).
Cache negative à 10-60 s pour ne pas frapper les clés manquantes.
Échauffement massif lors de la sortie/skating : listes de clés chaudes, read-ahead, refresh arrière-plan.
Dégradation et follbacks
Graceful Degradation : coupez les fiches mineures lorsque la latence augmente (réponse moins détaillée, arrêt des enrichissements).
Timeouts doux : retournez la réponse de base/cache au lieu de 5xx.
Fail-open/Fail-closed - documentez explicitement pour chaque appel.
Observation et profilage
Remorquage de distribution : dormeurs sur chaque hop, sampling des queues (tail-based).
RED/USE метрики: Rate, Errors, Duration / Utilization, Saturation, Errors.
Top-N itinéraires « lents » quotidiennement.
Profileurs (alloc/cpu/lock) en vente à faible surchauffe (eBPF/async-profiler/Flight Recorder).
Synthétiques de différents ASN/réseaux et canaux mobiles.
Tests de performance
Tests Latency-SLO (p95/p99) avec paiement réel et variabilité.
Scénarios Chaos : dégradation DNS, augmentation des pertes de paquets, retards TLS, store « lent ».
Cold-start/scale-up : mesurez les premières minutes après la sortie lorsque les caches sont vides.
Divisez les pools de charge par script (n'interférez pas avec les tests de lecture/écriture).
Mini-modèles
Politique des temporisateurs/rétroactifs (pseudo)
yaml timeouts:
connect: 100ms tls_handshake: 150ms request_p95_budget: 80ms retries:
max_attempts: 2 backoff: exp_jitter(10ms..60ms)
retry_on: [CONNECT_ERROR, TIMEOUT, 502, 503, 504]
hedging:
enabled: true threshold: p95 + 10ms cancel_extra_on_first_success: true circuit_breaker:
error_rate_threshold: 5%
p95_threshold_increase: 30%
half_open_after: 10s
Pools et bulkhead's
yaml pools:
checkout:
max_conns: 256 per_host: 64 queue: 8 # small analytics queue:
max_conns: 64 queue: 4
Réponse avec dégradation
json
{
"status": "ok",
"profile": { "id": "u123", "name": "…"},
"recommendations": "degraded, "//disabled the heavy part
"served_from": "edge-cache",
"trace_id": "…"
}
Cas d'application
iGaming/finance : autorisation de paiement <200 ms p95, limites/solde - lecture à partir de projections régionales, enregistrements - idempotent avec la version.
Marketing/recommandations : réponses <100 ms p95, cache d'indicateurs fich sur edge, modèles - pré-scoring + règles rapides sur le chemin chaud.
Clients mobiles : HTTP/3, reuse agressive de connexions, payload réduit (Protobuf), temps de garde et cache hors ligne.
Anti-modèles
Longues files d'attente devant les workers : « belle moyenne » et p99 morts.
Retraits en cascade sur chaque couche sans coordination.
Un « méga cache » global sans handicap et sans échauffement.
Les temporuts flous (partout « par défaut ») sont des queues non contrôlées.
Un pool commun de connexions pour tout le trafic est le verrouillage en ligne.
Logique lourde sur edge avec des effets stateful.
La télémétrie désactivée des queues - vous « ne voyez pas » p99.
Chèque-liste de production
- Il y a un budget de retard sur les hops et les temporuts en dessous.
- Inclus HTTP/2/3, TLS 1. 3, pools de connexions et warm-up.
- Hiérarchie des caches, liste des clés chaudes et stratégies de réchauffage.
- Lire-local/Write-global et charder les clés chaudes.
- Backpressure explicite, petites files d'attente, circuits-breakers et bulkhead.
- Retraits avec gitter, idempotence, couverture limitée.
- Tracing avec les étiquettes de région/version/client ; surveillance p95/p99.
- Tests de perf avec synthétique sur ASN/mobile, scénarios cold-start et chaos.
- Les procédures de dégradation et de folleback sont documentées.
- p95/p99 correspondent à SLO sur charge réelle.
FAQ
Pourquoi p99 est-il plus important que la moyenne ?
Parce que les utilisateurs sont confrontés aux queues, pas à la moyenne. p99 montre « combien il fait vraiment mal ».
Faut-il inclure la couverture partout ?
Non. Il est utile pour les résidus rares dans les voies critiques et seulement avec des limites strictes/idempotence.
Comment réduire le démarrage à froid ?
Chauffage des caches/connexions, pré-compilation/JIT, minimisation des initialisations lazy, pools warm.
Peut-on « battre le réseau » ?
En partie : HTTP/3, edge-POP, Anycast, payload compact, connection reuse et timeouts intelligents.
Résultat
L'architecture à faible latence est un système d'arrangements et de discipline : budget de latence, proximité des données, petites files d'attente, retraits prévisibles, hiérarchies de cache, protocoles corrects et observabilité impitoyable des queues. En suivant ces principes, vous gardez p95/p99 dans une prise sans sacrifier la stabilité et le portefeuille.