Back home

Taux de réussite du cache et qualité de la politique de cache

Le taux de réussite n'est qu'un indicateur de résultat. Ce qui détermine réellement le coût du système, c'est le mode de défaillance, la pression de retour et le rayon de propagation des erreurs.

Lorsque de nombreuses équipes parlent de mise en cache, la première chose qu’elles disent est le taux de réussite.

Un taux de réussite de 95 % semble bien ; 98 % semble être optimisé ; 99% donnent même l’illusion que le système a été « apprivoisé ».

Mais quand quelque chose ne va pas en ligne, tout le monde est souvent confronté à un autre ensemble de problèmes lors de l’examen : la base de données est pénétrée après l’expiration d’un certain lot de clés en même temps, les utilisateurs voient toujours les anciennes données dans l’heure qui suit la modification du prix, le nœud de cache tremble et les requêtes les plus coûteuses touchent toutes directement la base de données principale.

Mon jugement est simple : **Le but de la stratégie de cache est de contrôler le coût des « échecs ». ** Un taux de réussite élevé signifie uniquement que de nombreuses requêtes sont lues dans le cache ; cela ne signifie pas que la conception des défaillances est correcte, cela ne signifie pas que le coût du retour à la source est contrôlable, et cela ne signifie pas que les erreurs seront limitées à une petite plage.

Si un cache augmente le taux de réussite de 92 % à 99 %, mais au prix de rendre plus difficile l’invalidation, la localisation des données sales et plus susceptible de former une tempête de retour à l’origine pendant la gigue, alors il ne s’agit probablement pas d’une optimisation, mais déplace simplement la complexité de la base de données vers un autre coin.

La question n’est pas “combien de hits”, mais “où frapper quand vous ratez”

L’indicateur du taux de réussite présente un défaut naturel : il aplatit la répartition du chaud et du froid.

Une interface reçoit un million de requêtes par jour, dont 990 000 lisent des détails sur des produits populaires, et les 10 000 restantes lisent des produits à longue traîne. Mettez en cache les données populaires et le taux de réussite sera immédiatement très bon. Mais si ces 10 000 erreurs de longue traîne surviennent sur la requête la plus lente et la plus coûteuse qui implique également la jointure de tables, la pression sur la base de données ne sera peut-être pas moindre qu’on ne l’imaginait.

En d’autres termes, le taux de réussite est compté comme « nombre de fois », mais le coût du système est souvent calculé comme « prix ». **

Cela montre également que certaines équipes voient clairement de beaux indicateurs de cache, mais le processeur de la base de données ne peut toujours pas ralentir : le cache bloque les requêtes bon marché, et les échecs très coûteux s’exécutent toujours à nu.

Lorsque je juge une stratégie de mise en cache, je préfère examiner trois choses en premier :

  1. Manquer la partie la plus coûteuse de la demande ;
  2. Si les échecs se produiront de manière concentrée plutôt qu’uniformisée ;
  3. La contrainte sera-t-elle transmise à l’aval après le raté ?

Ces trois questions sont plus proches du coût réel que « le taux de réussite global a-t-il encore augmenté de 2 points ?

Ce qui détermine réellement la qualité du cache est généralement la méthode d’échec.

De nombreux accidents de cache sont essentiellement dus à une « conception de défaillance trop grossière ».

L’approche la plus courante consiste simplement à définir une durée de vie. La mise en œuvre est simple et les indicateurs sont faciles à améliorer, car tant que le TTL est suffisamment long, le taux de réussite n’est généralement pas trop mauvais. Mais il existe deux problèmes typiques avec les schémas TTL.

Premièrement, cela laisse le temps de décider de la date d’expiration des données, plutôt que des changements commerciaux. **

Les prix ont changé, l’inventaire a changé, les autorisations ont changé, mais le cache est toujours actif. Bien sûr, le TTL peut être raccourci, mais une fois le TTL raccourci, la fréquence de retour à la source augmentera à nouveau. De nombreuses équipes oscillent entre « les anciennes données sont trop anciennes » et « la base de données est trop chargée ».

Deuxièmement, il est facile de créer des échecs de synchronisation. **

Si un lot de raccourcis clavier est écrit au même moment et utilise le même TTL, ils expireront probablement ensemble au même moment. Normalement, le taux de réussite est correct, mais dès qu’il atteint le point d’expiration, il y aura un pic de retour à la source instantané. Cela ne représente peut-être qu’une instabilité de cinq minutes sur le tableau de bord, mais c’est un véritable coup de poing pour la base de données et les services en aval.

Par conséquent, la chose la plus importante dans la conception du cache est souvent de savoir si le mécanisme de défaillance est aligné sur les changements métier.

Les modifications courantes incluent :

  • Utilisez les échecs déclenchés par les événements au lieu de vous fier uniquement au TTL ;
  • Ajoutez une gigue aléatoire au TTL pour empêcher les clés de hotspot d’expirer en même temps ;
  • Mettez le numéro de version ou l’horodatage dans la clé pour changer explicitement la génération de données ;
  • Autoriser le renvoi des anciennes valeurs pendant une courte période, mais actualisées de manière asynchrone en arrière-plan au lieu de renvoyer toutes les demandes ensemble à l’origine.

L’essentiel ici est que vous devez décider quand accepter les anciennes données, quand elles doivent être cohérentes immédiatement et quand vous préférez renvoyer le résultat de la rétrogradation plutôt que de faire exploser la base de données principale. ** Il s’agit de la stratégie de mise en cache, et le taux de réussite n’en est que l’ombre.

L’extension de la durée de vie ne fait souvent que repousser le problème.

J’ai vu beaucoup de “optimisations de cache” faites comme ceci : la base de données en ligne est sous pression, donc le TTL passe de 5 minutes à 30 minutes, puis à 1 heure. En conséquence, le taux de réussite a augmenté et la courbe de la base de données est devenue un peu plate, et l’équipe a annoncé que l’optimisation était terminée.

Le plus dangereux de cette approche est qu’elle est trop facile à paraître efficace à court terme.

Parce que la plupart des systèmes d’indicateurs sont meilleurs pour enregistrer « combien de requêtes sont enregistrées » et ne sont pas efficaces pour enregistrer « combien de données erronées sont enregistrées ». Lorsque les anciens prix, les anciennes configurations et les anciennes autorisations sont lus par un plus grand nombre d’utilisateurs, les pertes ne sont souvent pas immédiatement reflétées dans le panneau de cache, mais apparaîtront plus tard dans les plaintes, les indemnisations, les vérifications manuelles et les examens des accidents.

En particulier pour les types de données suivants, il est souvent déconseillé d’étendre grossièrement la durée de vie :

  • Données qui affecteront le règlement du montant ;
  • Données qui affectent les autorisations et la visibilité ;
  • Les données qui ne sont pas mises à jour fréquemment, mais qui doivent converger le plus rapidement possible une fois mises à jour.

Pour ce type de données, si le taux de réussite le plus élevé est obtenu par « reconnaissance retardée des changements », cela dépasse la précision. **

La partie la plus difficile de la mise en cache est de limiter les erreurs

Une situation courante consiste à considérer la mise en cache comme « une couche supplémentaire devant la base de données ». Cette compréhension n’est pas fausse, mais elle est trop optimiste.

La mise en cache dans les systèmes réels est une surface de contrainte qui amplifie les défauts de conception. Si la clé est conçue de manière trop épaisse, l’étendue de la défaillance sera trop grande ; si la clé est conçue de manière trop fine, l’utilisation de la mémoire et la complexité de la maintenance augmenteront ; l’assemblage des données est placé dans la couche cache, et il est facile de répéter les calculs lors du retour à la source ; le cache local et le cache distribué sont empilés ensemble, et il y aura une couche supplémentaire de problèmes de cohérence.

Je vais donc diviser la solution de mise en cache en deux questions à examiner :

  • Etes-vous habituellement heureux ou pas ?
  • Quand quelque chose ne va pas, est-ce que cela entraînera le ralentissement d’autres parties du système ?

Cette dernière question est généralement plus importante.

Une implémentation de cache plus fiable gérera souvent explicitement les éléments suivants :

v, ok := cache.Get(key)
if ok && !v.SoftExpired() {
  return v.Data
}

return singleflight.Do(key, func() any {
  fresh := db.Load(id)
  cache.Set(key, fresh, ttlWithJitter())
  return fresh
})

Ce qui est vraiment précieux ici, ce sont deux contraintes :

  • Lorsque la même clé est renvoyée à l’origine, une seule requête est autorisée à atteindre réellement la base de données ;
  • L’expiration donne au système une fenêtre d’actualisation contrôlable.

Ce type de conception n’atteint pas nécessairement le meilleur taux de réussite, mais il peut réduire considérablement les tempêtes de retour et l’amplification instantanée. Sans gigue, le système ressemble plus à un « ralentissement » qu’à un « effondrement ».

Un malentendu courant : traiter le taux de réussite du cache comme un KPI d’équipe

Une fois que le pourcentage d’atteinte devient un KPI, il est facile pour les équipes de travailler dans la mauvaise direction.

Parce que le moyen le plus simple d’améliorer le taux de réussite est souvent d’améliorer les résultats statistiques :

  • Étirer TTL ;
  • Mettez plus de données qui ne doivent pas être mises en cache ;
  • Utilisez des touches à grain plus grossier pour mélanger différentes scènes ensemble ;
  • Diviser l’interface pour la rendre compatible avec le cache aggrave la sémantique métier.

Ces actions peuvent améliorer l’apparence du graphique, mais elles soulèveront d’autres problèmes : la fenêtre de données sales sera plus longue, les pannes seront plus difficiles, le dépannage sera plus difficile, la mémoire sera plus coûteuse et les frontières commerciales seront floues.

Une approche plus saine consiste à examiner la mise en cache avec les métriques suivantes :

  • Miss P95/P99 met du temps à revenir à la source ;
  • Nombre de clés de point d’accès de retour à la source simultanées ;
  • Taux d’erreur et pic de base de données après invalidation du cache ;
  • Le temps nécessaire aux données pour converger vers de nouvelles valeurs après la mise à jour ;
  • Combien de chemins de code et d’actions opérationnelles supplémentaires sont introduits pour maintenir le cache.

Ce n’est que lorsque ces coûts sont additionnés que le taux de réussite a un pouvoir explicatif. En y regardant seul, il est trop facile de se laisser berner.

Contre-exemple : dans certains scénarios, le taux de réussite doit être aussi élevé que possible

Vous ne pouvez pas le dire à mort.

Si les données sont naturellement stables, ou simplement une ressource immuable, comme des fichiers statiques, des configurations versionnées, du contenu de distribution CDN et des tables de dictionnaire qui changent rarement, alors le taux de réussite est en effet un objectif très important. Parce que dans ce genre de scénario, « plus ancien » n’est pas un problème sérieux, l’échec est relativement simple et le chemin de retour à la source est généralement clair et contrôlable.

Il existe également des systèmes internes basés sur des outils dans lesquels la quantité de données n’est pas importante, l’écriture est peu fréquente et le coût commercial des lectures sales occasionnelles est également très faible. Dans ce cas, une solution TTL simple est probablement la bonne. En apparence, il semble haut de gamme, mais en réalité, il est plus proche d’être assez bon marché.

Cet article s’oppose donc à ce que le taux de réussite soit retiré de son contexte et à son utilisation seule comme preuve du succès du cache.

Résumé

Pour juger si une solution de mise en cache est fiable, je voudrais d’abord demander : **Que se passera-t-il lorsque l’échec le plus coûteux de ce système se produira ? **

Si la réponse est « juste un peu plus lent, le système peut encore être stable », alors le cache est probablement conçu.

Si la réponse est « le taux de réussite est généralement très élevé, mais une fois qu’il échoue, il pénètre dans la base de données principale et réduit la précision », alors il s’agit simplement d’un danger caché qui semble fonctionner dur en temps ordinaire.

La mise en cache ne consiste jamais simplement à « rapprocher les données ». Ce qu’il teste réellement, c’est la manière de gérer les changements, les échecs et les coûts. Un taux de réussite élevé signifie que vous avez bien fait la première moitié de la phrase au maximum ; c’est la seconde moitié de la phrase qui détermine si la stratégie en vaut la peine.

FAQ

What to read next

Related

Continue reading