Le cache qui vit dans la mémoire
Près d'un cinquième des images de compteur que dessine ce service ne changent plus rien. Un script de suivi de souris de la génération précédente recharge l'image à chaque mouvement, et depuis que ces requêtes n'incrémentent plus rien, deux d'affilée produisent la même image, octet pour octet.
Un candidat évident pour un cache. Les décisions intéressantes portaient sur l'endroit où le mettre et sur ce qui devait servir de clé.
Pas sur le disque
Cela tourne sur un Raspberry Pi, et le disque est une carte SD. Y mettre en cache les images dessinées aurait représenté environ 70 Mo d'écriture par jour, en échange d'une économie mesurée de 1,6 minute de calcul par jour.
C'est un mauvais échange. Les cartes SD meurent d'écrire, et ce qu'on achète est une erreur d'arrondi sur une machine qui n'est pas limitée par le calcul. Le cache vit donc dans /dev/shm, c'est-à-dire tmpfs, c'est-à-dire la mémoire vive. Mesuré là : 0,027 ms en lecture, 0,036 ms en écriture, 1,9 Go libres.
Tout disparaît au redémarrage. Pour un cache ce n'est pas une perte, c'est le cas normal.
Redis tourne sur le même Pi. Il n'a pas été retenu, pour une raison qui n'a rien de technique : il appartient à une autre application et est protégé par mot de passe pour elle. Partager une instance lierait deux services sans rapport, de sorte qu'une mauvaise journée de l'un devienne une mauvaise journée de l'autre.
La clé contient les nombres
La clé de cache habituelle est une identité plus une expiration, et l'expiration est un pari : rien d'important n'a changé ces cinq dernières minutes. Pour un compteur, ce qui change est exactement ce qui est affiché.
Les valeurs affichées entrent donc dans la clé. Si un nombre change, c'est une autre clé, et l'image est redessinée. Le pari disparaît au lieu d'être pris avec soin. Chaque visite comptée incrémente au moins le total depuis toujours, donc aucune visite comptée ne peut recevoir une image périmée. L'expiration qui subsiste n'est plus qu'une borne supérieure pour les valeurs qui ne sont pas dans la clé — les chiffres hebdomadaires, mensuels et annuels.
Ce qu'il a fallu vérifier d'abord
Un cache n'est sûr que si ce qu'il garde est fonction de sa clé. C'est une affirmation sur chaque motif, et elle a été vérifiée plutôt que supposée :
- aucun motif n'utilise
rand(),mt_rand(),shuffle()ouuniqid() - aucun motif ne lit l'horloge plus finement qu'à l'heure
- les paramètres de suivi de l'ancien script ne sont lus nulle part dans l'arbre
Ce dernier point a produit le plus bel échec de tout l'exercice. Tant que ces paramètres faisaient partie de la clé, chaque requête portait des coordonnées de souris légèrement différentes, donc chaque clé était unique. Le cache a tourné une journée entière et a enregistré 13 succès. Il fonctionnait parfaitement et ne faisait rien, ce qui est la sorte de panne la plus difficile à remarquer.
Et si quelque chose échoue ici — répertoire illisible, disque plein, entrée corrompue — l'image est dessinée normalement. Un cache ne doit jamais être la raison pour laquelle un compteur n'apparaît pas.