Stratégies de cache
1) Pourquoi cacheter et où le faire
Cache est une couche de mémoire rapide qui réduit la latence et la charge sur les ressources coûteuses (CPU/OBD/API externes). Objectifs importants :- Vitesse (p95/p99), coût (moins d'egress/CPU), stabilité (moins de dépendances sous le pic).
- Lissage des pics et isolement des « voisins bruyants ».
1. Client (navigateur/mobile) - cache HTTP, IndexedDB, stockage local.
2. Edge/CDN - Les nœuds POP sont plus proches de l'utilisateur, mettent en cache la statique et une partie de l'API.
3. L7-gateway/Reverse-proxy - Nginx/Envoy/Varnish (microcash, SWR).
4. Cache de service - Redis/Memcached à l'intérieur du cluster.
5. Intra-process - in-memory (Cafeine/Guava/LRU-map).
6. Cache dans la base de données - vues matérielles, index secondaires.
Règle : fixez le plus près possible du consommateur, mais gardez la vérité une fois.
2) Modèles de cache
2. 1 Cache-aside (“lazy loading”)
L'application lit d'abord à partir du cache ; en cas d'échec, à partir de la source, puis écrit dans le cache.
Avantages : simplicité, contrôle. Inconvénients : démarrages froids, fenêtres de désaccord.
2. 2 Read-through
La lecture se fait toujours par l'intermédiaire d'un cache qui se dirige vers la source en cas d'échec (bibliothèque/couche de proxénétisme).
Il est commode de centraliser les politiques de TTL/sérialisation.
2. 3 Write-through / Write-back (write-behind)
Write-through : écriture dans le cache et la source synchrone → cohérence supérieure, latence supérieure.
Write-back : écriture dans le cache, écriture flash asynchrone dans la source → rapide, mais risque de perte et de conflit.
2. 4 Refresh-ahead (proactive)
Prédit « TTL expirera bientôt » et met à jour la clé dans le fond, empêchant stampede.
2. 5 Negative caching
Le cache « pas de données/404/vide » sur un court TTL réduit la charge sur la source.
2. 6 Micro-caching
TTL très courts (0. 5-5 c) sur L7 pour « presque dynamique » (listes, principal) - réduit considérablement les queues.
3) HTTP-cache : titres et contrôle
3. 1 Titres de base
`Cache-Control`: `max-age`, `s-maxage` (для shared кэшей), `public/private`, `no-store`, `stale-while-revalidate`, `stale-if-error`.
Validateurs : 'ETag', 'Last-Modified'.
Demandes avec conditions : 'If-None-Match', 'If-Modified-Since' → 304 Not Modified.
3. 2 Vary et clés
« Vary : Accept-Encoding, Autorisation, Cookie, Accept-Language » - forme différentes options de cache. Minimisez 'Vary' pour ne pas « faire sauter » la cardinalité.
3. 3 Exemple de réponse HTTP
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60
ETag: "a1b2c3"
Vary: Accept-Encoding
4) Conception de clés et TTL
4. 1 clés
Structurer : 'tenant : user : {id} : profile : v3' (activer la version du schéma).
Éviter les PII dans la clé.
Pour les collections, clé + paramètres de requête (normalisés et triés).
4. 2 TTL et cohérence
Un court TTL réduit le désaccord, mais augmente les défauts.
Pour les données critiques, les validateurs (« ETag ») et SWR (stale-while-revalidate).
Pour ceux qui changent rarement, un long TTL + « bombes » d'invalidité.
4. 3 Versioning/Basting
Si les modifications ne sont pas compatibles, modifiez le préfixe/version de la clé ('v2 → v3').
Pour les ressources statiques : Contenu hash dans le nom du fichier.
5) Handicap : stratégies et pratiques
5. 1 Suppression directe
'DEL key '/' PURGE 'sur le proxy. Danger : course entre le retrait et les lecteurs multiples.
5. 2 Tags/Clés Surrogate
Associez le document à un jeu de balises (catégorie/auteur). L'invalidité est une étiquette.
В Varnish/Edge — `Surrogate-Key: article:42 tag:author:7` + `BAN tag:author:7`.
5. 3 Handicaps event-driven
Pub/Sub (Kafka/NATS) : lorsque la source change, nous publions l'événement « invalidate ».
Les conseillers du cache écoutent et suppriment/mettent à jour les clés.
5. 4 Biphasé
D'abord, on marque la clé obsolète (soft TTL), on sert stale, on la met à jour et on la remplace atomiquement.
6) Lutte contre le stampede/dogpile et les clés chaudes
6. 1 Request coalescing (singleflight)
Un producteur met à jour la clé, les autres attendent le résultat (mutex/label « mis à jour »).
6. 2 Jitter к TTL
Ajoutez l'aléa (± 10-20 %) à la TTL pour éviter les protubérances synchrones.
6. 3 Soft-TTL + hard-TTL
Jusqu'à soft-TTL sont servis à partir du cache, parallèlement au trigerim refresh ; sur hard-TTL - nous considérons la faille.
6. 4 Clés chaudes
Caches locaux au-dessus des caches partagés (two-tier).
Réplication de la clé chaude en plusieurs chardes et sélection aléatoire (uniquement pour la lecture seule).
Rate limit pour mettre à jour une clé spécifique.
6. 5 Exemple Redis + Lua (croquis singleflight)
lua
-- SETNX lock with TTL to avoid deadlocks local ok = redis. call("SET", KEYS[1], "1", "NX", "EX", ARGV[1])
if ok then return "LOCKED"
else return "WAIT"
end
7) Stratégies de déplacement et de réception dans le cache
7. 1 Eviction
LRU : simple et bon pour la localisation.
LFU : mieux avec des clés chaudes « à longue durée de vie ».
ARC/TinyLFU : équilibre recency/frequency.
7. 2 Admission (entrée)
Ne laissez pas entrer les objets rares géants (filtres TinyLFU/Bloom).
Compression de grandes valeurs (LZ4/Zstd) à la frontière « taille/latence ».
8) Chardonnages et topologies
8. 1 Consistent hashing
Répartit les clés de façon stable sur les noeuds, réduit les mouvements lors de la croissance/compression du cluster.
8. 2 Topologies Redis/Memcached
Redis Cluster (slots/chardes), Sentinel (faussaire), réplication read-only.
Memcached est un client-side sharding (ketama hashing), sans réplication au niveau du serveur.
8. 3 Local + distribué
Cascade : in-proc (micro-TTL/LRU) → Redis (TTL plus long) source →.
Faites attention aux deux points TTL et validateurs de cache.
9) Edge, CDN et L7-cache
9. 1 Micro-cache на Nginx
nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:100m inactive=10m;
map $request_method $skip_cache { default 0; POST 1; PUT 1; DELETE 1; }
server {
location /api/list {
if ($skip_cache) { add_header Cache-Control "no-store"; }
proxy_cache api;
proxy_cache_valid 200 2s; # micro-cache proxy_cache_use_stale error timeout updating;
proxy_cache_background_update on; # SWR add_header X-Cache $upstream_cache_status;
proxy_pass http://upstream;
}
}
9. 2 Envoy (SWR et conditions)
yaml http_filters:
- name: envoy. filters. http. cache typed_config:
"@type": type. googleapis. com/envoy. extensions. filters. http. cache. v3. CacheConfig typed_config:
"@type": type. googleapis. com/envoy. extensions. http. cache. file_system_http_cache. v3. FileSystemHttpCacheConfig cache_path: "/var/cache/envoy"
9. 3 Varnish (Surrogate keys)
Utilisez 'Surrogate-Key' et 'ban' par tags pour l'invalidité par lots.
10) Cache et cohérence des données
10. 1 Read-your-writes
Pour les profils/paniers personnalisés, fournissez des TTL courts ou un enregistrement à travers le cache (write-through) ou un marquage client (bypass pour N secondes après l'enregistrement).
10. 2 Eventual vs Strong
Pour les recommandations/analyses - eventual + long TTL.
Pour l'argent/état des commandes - TTL court, validation, parfois sans cache sur les chemins critiques.
10. 3 Invariants
Ne tapez pas les champs qui affectent la sécurité/ACL sans TTL rigoureux et sans revérifier.
11) Observabilité, SLO et contrôle
11. 1 Métriques
hit_ratio (общий и per-route), byte_hit_ratio, miss_rate.
stampede_prevented_total, refresh_ahead_total, ban/purge_total.
Latence : p50/p95/p99 du cache vs de la source.
hot_keys_topN et leurs QPS/octets.
11. 2 Logs et traçages
Loger « X-Cache : HIT/MISS/STALE/UPDATING ».
Dans les tracés, notez la source de la réponse ('cache = vrai', 'tier = edge' service 'local').
11. 3 approche SLO
Exemple : "pour API/catalogue p99 ≤ 250 ms, cache hit ≥ 85 %, stampede ≤ 0. 1 % des requêtes
11. 4 Runbooks
« Les échecs grandissent » → vérifier la TTL, l'échauffement/invalidité, les clés hot, la taille du cache et la politique d'acceptation.
12) Sécurité et multi-ténacité
Incorporez tenant-id dans les clés (et dans « Vary » en HTTP).
Ne jetez pas les réponses privées comme 'public'.
Crypter le cache avec des données sensibles ou ne stocker que les non-PII/ID.
13) Recettes types
13. 1 Catalogue/bande (presque dynamique)
Edge-microcash 1-3 avec + SWR, à l'intérieur - Redis de 15-60 s, handicapé par les événements de renouvellement.
13. 2 Profil de l'utilisateur
Cache-aside avec TTL 30-120 s, bypass 5-10 s après mise à jour du profil (cookie/header), ou write-through.
13. 3 Cours/manuels de valeur
Long TTL (minutes-heures) + handicap ciblé lors de la publication de nouvelles données ; 'ETag'pour les GET conditionnels.
13. 4 Délivrance de recherche
Edge-microcash 1-2 s, à l'intérieur - refresh-ahead et coalescing, normaliser les paramètres query dans la clé.
14) Anti-modèles
Cache sans handicap : l'espoir n'est que TTL → de longues fenêtres d'inattention.
Gigantesque « Vary » : « explosion » des options → hit-rate bas.
Cache unique pour prod/experiments → la pollution.
Pas de protection contre le stampede → des pics à la source à l'expiration de la TTL.
Cash argent/droits/ACL sans garanties strictes.
Compression « total consécutif » - CPU superflu, détérioration p99 dans les petites installations.
15) Chèque de mise en œuvre
- Définir les niveaux de cache et leurs objectifs (edge/service/local).
- Concevoir les clés (versioning, tenant, normaliser les paramètres).
- Sélectionnez un modèle (cache-aside/read-through/refresh-ahead).
- Configurez TTL/soft-TTL/jitter, activez le SWR.
- Implémentez coalescing/singleflight, protection contre le stampede.
- Organiser un handicap (événements, tags, purge/ban).
- Entrez les métriques « hit-ratio/latence » et « X-Cache ».
- Effectuer des tests de charge avec des clés chaudes.
- Laissez tomber SLO et runbooks.
- Vérifier la sécurité/tenant-isolation et 'Vary'.
16) FAQ
Q : Que choisir - cache-aside ou read-through ?
R : Pour des services simples - cache-aside. Il faut une centralisation et une politique unique - read-through.
Q : Comment comprendre la TTL optimale ?
R : Repoussez-vous de l'obsolescence admissible, de la fréquence des mises à jour et de la cible hit-rate ; ajoutez jitter et observez p95/p99/coût.
Q : Quand le write-back est-il approprié ?
R : Pour les flux fortement chargés, où la consistance eventuelle est acceptable et il y a une file d'attente/log fiable pour la « finalisation ».
Q : Les réponses autorisées peuvent-elles être cachées ?
A : Oui, mais marquer 'private'et/ou inclure tenant/user dans la clé/' Vary '. Pour truly-private, le cache client.
Q : Comment chauffer le cache ?
R : Listes de clés populaires, background-wormer, répliques des logs, échauffement avant la sortie/pic (Black Friday, etc.).
17) Résultats
La mise en cache efficace est la conception de clés + TTL + raisonnable, un modèle bien choisi, renforcé par un handicap par événement, SWR/refresh-ahead et une protection contre le stampede. Séparez le cache en niveaux (client/edge/service), ajoutez l'observabilité et le SLO - et obtenez des queues de latence stables, un coût prévisible et une résistance aux pics de charge.