Persistance Redis dans Docker sans en faire une application disque lente

Cet article vous a aidé ?

Vous avez activé la persistance Redis dans un conteneur et soudainement votre base « en mémoire » a commencé à se traîner comme si elle montait des rochers en pente.
Pics de latence, débit qui chûte, et l’équipe applicative jure que rien n’a changé — sauf la partie où vous avez demandé à Redis de ne pas tout oublier au redémarrage.

C’est la taxe de durabilité de Redis. La bonne nouvelle : vous pouvez la payer dans une monnaie sensée (patterns d’E/S prévisibles et blocages bornés), au lieu de signer un chèque en blanc à votre SSD.
La mauvaise nouvelle : Docker facilite le mauvais choix de chemin de stockage, puis on reproche à Redis d’être « lent ».

Faits et courte histoire qui importent vraiment

Les débats sur la persistance Redis peuvent devenir religieux. Restons concrets : voici quelques points de contexte qui expliquent les commandes d’aujourd’hui et leurs arêtes vives.

  1. Redis a commencé comme un serveur en mémoire avec le disque en filet de sécurité optionnel. La persistance est ajoutée en couche, pas fondamentale — vous devez donc l’aligner sur votre charge de travail.
  2. Les snapshots RDB sont arrivés en premier et sont volontairement « massifs ». Ils privilégient les écritures peu fréquentes et lourdes plutôt que des petites écritures constantes, avec un coût lié au fork et au copy-on-write.
  3. L’AOF (Append Only File) a été ajouté pour réduire la fenêtre de perte de données. Il journalise les commandes d’écriture ; la relecture reconstruit le dataset au redémarrage. Idéal pour la durabilité ; facile à mal utiliser.
  4. appendfsync everysec existe parce que « toujours » coûte cher. Il vise une fenêtre de durabilité d’une seconde tout en lissant l’amplification d’écriture.
  5. Redis réécrit l’AOF pour éviter qu’il ne grossisse indéfiniment. Cette réécriture est une tâche d’arrière-plan qui mord encore, car elle concurrence les I/O et la mémoire.
  6. Fork + copy-on-write signifie que la persistance peut augmenter l’utilisation mémoire. Pendant le snapshot ou la réécriture, les pages modifiées sont dupliquées. En conteneurs, c’est comme ça qu’on rencontre le killer OOM.
  7. Les systèmes de fichiers copy-on-write de Docker ne sont pas magiques. Mettez des fichiers à fort écriture sur overlay2 et vous mesurerez des « acrobaties métadonnées » du système de fichiers, pas Redis.
  8. Le comportement de fsync est un contrat noyau + stockage, pas une promesse de Redis. Si votre stockage ment sur les flushs ou si votre hyperviseur triche, vos écritures « durables » deviennent théâtrales.
  9. La persistance Redis n’est pas une stratégie de sauvegarde. C’est un mécanisme de récupération après crash. Les sauvegardes exigent rétention, copies hors hôte et tests de restauration séparés.

Une citation pour rester lucide : idée paraphrasée — Charity Majors : « Tout échoue ; la différence est de savoir si vous pouvez comprendre et récupérer rapidement. »

Modèle de persistance : ce que Redis écrit réellement et quand ça pose problème

Snapshots RDB : grosses écritures, longues ombres

La persistance RDB écrit un snapshot point-in-time sur disque. C’est efficace si vous acceptez une fenêtre de perte et que vous voulez des fichiers compacts et des redémarrages rapides.
Le coût apparaît en deux endroits : CPU/mémoire pendant le fork et I/O disque pendant l’écriture du snapshot.

Le fork lui-même est généralement peu coûteux, jusqu’à ce que votre dataset soit volumineux et que la fragmentation mémoire soit élevée. Alors les blocages dus au fork peuvent provoquer des pics de latence.
Le vrai coût sournois est le copy-on-write : pendant que Redis écrit le snapshot dans un processus enfant, le parent continue de servir. Chaque page modifiée est dupliquée.
C’est une pression mémoire supplémentaire et du travail en plus.

Dans Docker, la pression mémoire est moins indulgente. Le conteneur ne se soucie pas que vous ayez « seulement 60% d’utilisation » — il se soucie que vous ayez franchi la limite maintenant.
Avec RDB activé, votre mémoire de pic n’est pas la taille du dataset en état stable. Planifiez en conséquence.

AOF : beaucoup d’écritures, plus des « semaines de régime » périodiques

L’AOF journalise les opérations. Cela signifie des ajouts fréquents, plus fsync selon la configuration.
Si vous mettez appendfsync always, Redis appellera fsync à chaque écriture. C’est la durabilité maximale et l’occasion maximale de détester votre sous-système de stockage.

La posture production par défaut est appendfsync everysec. Redis ajoute dans le cache de pages du noyau et demande au noyau de vider une fois par seconde.
Si le noyau ne suit pas, Redis peut encore subir des blocs parce que le tampon se remplit, ou parce que le backend de stockage transforme fsync en événement bloquant avec une latence de queue.

Ensuite il y a la réécriture AOF. Avec le temps, l’AOF contient des commandes redondantes. Redis le réécrit pour le compacter.
Les réécritures sont en arrière-plan, mais elles ne sont pas « gratuites ». Elles allouent, scannent, écrivent de gros fichiers séquentiels et peuvent entrer en collision avec le chemin d’écriture de votre application.

Les réglages de durabilité qui décident votre budget de latence

  • appendfsync always : fenêtre de perte la plus faible, sensibilité à la latence la plus élevée. À utiliser seulement si c’est vraiment nécessaire et si votre stockage est éprouvé.
  • appendfsync everysec : compromis de production typique. Fenêtre de perte d’une seconde ; peut encore provoquer des pics sous contention I/O.
  • appendfsync no : le noyau décide quand vider. C’est « rapide jusqu’au redémarrage », et parfois « pas rapide non plus ».

Petite blague (courte et pertinente) : Si vous activez appendfsync always sur un stockage réseau bon marché, vous avez inventé une nouvelle base de données : Redis Mais Plus Lent.

Ce que Docker change (et ce qu’il ne change pas)

Redis dans un conteneur reste Redis. Même code de persistance, même modèle de fork, mêmes appels fsync.
Ce qui change, c’est le chemin vers le disque : systèmes de fichiers en overlay, plugins de volume, limites de cgroup, et l’habitude de traiter les conteneurs comme des animaux jetables tout en s’attendant discrètement à ce qu’ils se souviennent de choses.

Stockage Docker : overlay2, bind mounts, volumes nommés, et pourquoi vous devez vous en soucier

Ne mettez pas la persistance Redis sur la couche modifiable du conteneur

La couche modifiable du conteneur (overlay2 sur la plupart des installations Linux) convient pour les logs et petits états. L’AOF de Redis n’est pas du « petit état ».
Overlay2 ajoute une sémantique copy-on-write et des opérations métadonnées supplémentaires. Sous des schémas d’écriture intensifs, cela peut ajouter de la latence et amplifier les écritures.

Si vous ne retenez qu’une règle : les fichiers de persistance Redis doivent vivre sur un vrai montage — un volume nommé ou un bind mount soutenu par un système de fichiers que vous comprenez.

Bind mount vs volume nommé

Un bind mount pointe vers un chemin hôte. Il est transparent et facile à inspecter. Il hérite aussi des options de montage de l’hôte, ce qui est à la fois puissance et risque.
Un volume nommé est géré par Docker sous /var/lib/docker/volumes. C’est plus propre opérationnellement et évite en général les incidents de « oups mauvais droits ».

En termes de performances, les deux peuvent être excellents. Le facteur décisif est généralement la gouvernance : qui gère le chemin, les sauvegardes et les options de montage.

Système de fichiers et options de montage : vous ne choisissez pas une religion, vous choisissez des modes de panne

Pour la persistance Redis, en général vous souhaitez :

  • fsync rapide et cohérent : SSD/NVMe local bat le stockage réseau pour la latence en queue.
  • débit d’écriture stable : la réécriture AOF est un écrivain séquentiel ; RDB est aussi un gros écrivain séquentiel.
  • latence prévisible sous pression : pas « bonne en moyenne, tragique au p99.9 ».

Ext4 avec des valeurs par défaut sensées est ennuyeux et fiable. XFS est aussi solide. Si vous utilisez ZFS, vous pouvez obtenir d’excellents résultats, mais seulement si vous savez comment les écritures sync sont gérées.
Si vous ne le savez pas, vous l’apprendrez à 3h du matin.

Stockage qui ment sur les flushs

Certaines couches accusent réception des flushs trop tôt. Certains contrôleurs RAID cachent dans leur cache sans batterie. Certains volumes cloud ont un modèle de flush qui est « finalement cohérent en esprit ».
Redis appellera fsync. Si la pile triche, votre AOF peut être « écrit avec succès » et quand même disparaître après une coupure de courant.

C’est pourquoi les exigences de durabilité doivent inclure la plateforme de stockage, pas seulement la config Redis.

Que lancer en production : recettes opinionnées de persistance

Recette A : « J’ai besoin d’un cache rapide qui survit aux redémarrages » (commun)

Utilisez les snapshots RDB, acceptez une fenêtre de perte (minutes) et gardez Redis rapide.
Si votre source de vérité est ailleurs (base de données, journal d’événements), Redis est un cache avec des avantages.

  • Activez RDB avec des points de sauvegarde raisonnables.
  • Désactivez l’AOF.
  • Mettez dump.rdb sur un volume hôte.
  • Surveillez la durée des snapshots et le temps de fork.

Recette B : « Je peux perdre 1 seconde, pas 10 minutes » (la plupart des usages étatful)

Utilisez AOF avec appendfsync everysec.
Gardez le comportement de réécriture prévisible. Gardez le chemin disque propre. Ne lancez pas ça sur overlay2 puis n’ouvrez pas un ticket « Redis est lent ».

  • Activez l’AOF.
  • appendfsync everysec.
  • Gardez RDB soit désactivé soit comme snapshot périodique additionnel (dépend de la stratégie de restauration).
  • Assurez-vous d’avoir une marge mémoire pour la réécriture.

Recette C : « Je veux vraiment durable » (rare et coûteux)

Si vous exigez « aucune écriture reconnue n’est perdue », Redis seul n’est pas toute la réponse. Pourtant, si vous insistez :

  • Envisagez AOF always seulement si votre stockage est éprouvé pour les écritures sync.
  • Utilisez la réplication et configurez WAIT côté client pour des accusés de réception de réplication synchrone.
  • Testez les scénarios de crash, pas seulement les benchmarks.

Petite blague (courte et pertinente) : « Always fsync » c’est comme porter un casque au bureau — plus sûr, mais vous trébucherez toujours sur le tapis.

Paramètres que j’aime réellement (et pourquoi)

Pour de nombreuses charges en production :

  • appendonly yes
  • appendfsync everysec
  • no-appendfsync-on-rewrite yes pour réduire les blocages induits par la réécriture (en acceptant une fenêtre de perte légèrement plus grande pendant la réécriture)
  • auto-aof-rewrite-percentage et auto-aof-rewrite-min-size réglés pour que les réécritures aient lieu avant que le fichier ne devienne absurde

Le paramètre controversé est no-appendfsync-on-rewrite. Si vous ne pouvez pas tolérer un risque de perte supplémentaire pendant la réécriture, ne l’activez pas.
Si vous pouvez, il vous offre souvent une stabilité de latence.

Conseils spécifiques aux conteneurs pour éviter un Redis disque-lent

  • Montez les fichiers de persistance sur un volume/bind mount, pas sur la couche du conteneur.
  • Limitez la mémoire de façon appropriée, mais laissez une marge pour le fork/la réécriture copy-on-write.
  • Attribuez suffisamment de CPU pour éviter que le thread fsync ne se fasse « voler » du temps CPU.
  • Ne mélangez pas le chemin de données avec des voisins bruyants (même disque pour logs, pulls d’images et fsync Redis).

Tâches pratiques : commandes, sorties et décision à prendre

Voici les vérifications que j’exécute quand quelqu’un dit « Redis est lent après qu’on a activé la persistance ». Chaque tâche inclut ce que la sortie signifie et la décision suivante.
Exécutez-les sur l’hôte Docker sauf indication contraire.

Tâche 1 : Vérifier le mode de persistance Redis depuis l’intérieur du conteneur

cr0x@server:~$ docker exec -it redis redis-cli CONFIG GET appendonly appendfsync save
1) "appendonly"
2) "yes"
3) "appendfsync"
4) "everysec"
5) "save"
6) "900 1 300 10 60 10000"

Ce que cela signifie : L’AOF est activé avec fsync chaque seconde ; les snapshots RDB sont aussi activés.

Décision : Si vous n’avez pas besoin des deux, désactivez-en un. Exécuter les deux augmente les I/O et les événements fork/réécriture. Préférez une méthode primaire de persistance.

Tâche 2 : Confirmer où Redis écrit les données (et si c’est sur overlay2)

cr0x@server:~$ docker exec -it redis redis-cli CONFIG GET dir dbfilename appendfilename
1) "dir"
2) "/data"
3) "dbfilename"
4) "dump.rdb"
5) "appendfilename"
6) "appendonly.aof"

Ce que cela signifie : Redis écrit dans /data à l’intérieur du conteneur.

Décision : Vérifiez si /data est un volume/bind mount. Si c’est simplement le système de fichiers du conteneur, corrigez cela maintenant.

Tâche 3 : Inspecter les montages Docker pour le conteneur

cr0x@server:~$ docker inspect redis --format '{{json .Mounts}}'
[{"Type":"volume","Name":"redis-data","Source":"/var/lib/docker/volumes/redis-data/_data","Destination":"/data","Driver":"local","Mode":"z","RW":true,"Propagation":""}]

Ce que cela signifie : Bien : /data est un volume Docker mappé vers un chemin hôte.

Décision : Si Type est manquant ou si Destination n’est pas /data, vous écrivez probablement sur overlay2. Déplacez la persistance vers un montage.

Tâche 4 : Identifier le système de fichiers qui supporte le répertoire de données

cr0x@server:~$ df -Th /var/lib/docker/volumes/redis-data/_data
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2 ext4  450G  120G  307G  29% /

Ce que cela signifie : Les données résident sur ext4 sur le système racine local supporté par NVMe.

Décision : Si cela montre un type de système de fichiers réseau (comme nfs) ou un disque partagé lent, attendez-vous à des douleurs fsync. Envisagez de déplacer les données Redis sur un SSD local.

Tâche 5 : Vérifier les options de montage qui affectent la durabilité et la latence

cr0x@server:~$ findmnt -no TARGET,FSTYPE,OPTIONS /var/lib/docker/volumes/redis-data/_data
/ ext4 rw,relatime,errors=remount-ro

Ce que cela signifie : Options ext4 standard. Rien d’évidemment dangereux comme data=writeback ici.

Décision : Si vous voyez des options exotiques que vous ne comprenez pas sur le montage de données Redis, arrêtez-vous et validez. « Inconnu » n’est pas une option de montage ; c’est un incident futur.

Tâche 6 : Mesurer la latence liée à la persistance depuis Redis lui‑même

cr0x@server:~$ docker exec -it redis redis-cli INFO persistence | egrep 'aof_enabled|aof_last_write_status|aof_last_fsync_status|aof_delayed_fsync|rdb_last_bgsave_status|rdb_last_bgsave_time_sec'
aof_enabled:1
aof_last_write_status:ok
aof_last_fsync_status:ok
aof_delayed_fsync:37
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:4

Ce que cela signifie : aof_delayed_fsync indique des opérations fsync qui ont pris plus de temps que prévu (le noyau n’a pas pu vider rapidement).

Décision : Si aof_delayed_fsync augmente lors des pics, concentrez-vous sur la latence et la contention du stockage, pas le CPU Redis.

Tâche 7 : Vérifier si la réécriture AOF est en cours et provoque des blocages

cr0x@server:~$ docker exec -it redis redis-cli INFO persistence | egrep 'aof_rewrite_in_progress|aof_current_size|aof_base_size|aof_pending_rewrite|aof_current_rewrite_time_sec'
aof_rewrite_in_progress:0
aof_current_size:2147483648
aof_base_size:1073741824
aof_pending_rewrite:0
aof_current_rewrite_time_sec:-1

Ce que cela signifie : Pas de réécriture pour l’instant ; l’AOF a doublé depuis la base. Une réécriture est probable bientôt selon les seuils.

Décision : Si les réécritures coïncident avec des pics de latence, ajustez les seuils de réécriture et confirmez la marge I/O. Envisagez des fenêtres de maintenance si vous ne pouvez pas stabiliser.

Tâche 8 : Confirmer que le conteneur n’est pas bridé CPU (la famine du thread fsync est réelle)

cr0x@server:~$ docker inspect redis --format '{{.HostConfig.NanoCpus}} {{.HostConfig.CpuQuota}} {{.HostConfig.CpuPeriod}}'
0 50000 100000

Ce que cela signifie : Le quota CPU est à 50% d’un cœur (50,000/100,000). Redis sous charge avec persistance peut souffrir si il est affamé CPU.

Décision : Si les pics de latence se corrèlent avec du throttling CPU, augmentez le quota CPU ou retirez-le. N’essayez pas de tromper la physique avec demi-cœur et écritures sync.

Tâche 9 : Vérifier la marge mémoire pour fork/réécriture

cr0x@server:~$ docker exec -it redis redis-cli INFO memory | egrep 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
used_memory_human:7.82G
maxmemory_human:8.00G
mem_fragmentation_ratio:1.41

Ce que cela signifie : Vous êtes pratiquement à la limite. Fork/réécriture va vous pousser en territoire OOM, surtout avec une fragmentation à 1.41.

Décision : Augmentez la marge de maxmemory (ou réduisez le dataset), ou acceptez que les événements de persistance puissent tuer le processus. Les conteneurs ne négocient pas.

Tâche 10 : Observer la latence disque réelle sur l’hôte (rapide et sale)

cr0x@server:~$ iostat -x 1 5
Linux 6.2.0 (server) 	01/03/2026 	_x86_64_	(8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.11    0.00    6.05    8.90    0.00   72.94

Device            r/s     rkB/s   rrqm/s  %rrqm  r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm  w_await wareq-sz  aqu-sz  %util
nvme0n1         12.00   1400.00     0.00   0.00    1.10   116.67  950.00  18000.00  120.00  11.20   22.30    18.95   21.40  98.00

Ce que cela signifie : Le disque est saturé (%util proche de 100), et l’attente d’écriture est élevée. Le fsync Redis va sentir ça.

Décision : Trouvez la contention : autres charges, tempêtes de logs, pulls d’images, sauvegardes, ou voisins bruyants sur le même appareil. Déplacez les données Redis ou isolez le disque.

Tâche 11 : Vérifier si l’hôte bride l’écriture des pages dirty

cr0x@server:~$ sysctl vm.dirty_background_ratio vm.dirty_ratio
vm.dirty_background_ratio = 10
vm.dirty_ratio = 20

Ce que cela signifie : Valeurs plutôt par défaut. Si les ratios dirty sont trop bas, le noyau peut forcer le writeback synchrone plus souvent ; trop hauts et cela peut causer de grosses rafales d’écriture.

Décision : Si vous observez des blocages périodiques de plusieurs secondes qui coïncident avec le writeback, ajustez prudemment et testez. Ne « cargo cultisez » pas des valeurs sysctl sans tester.

Tâche 12 : Confirmer que Redis persiste réellement sur disque (fichiers et tailles)

cr0x@server:~$ ls -lh /var/lib/docker/volumes/redis-data/_data
total 3.1G
-rw-r--r-- 1 redis redis 2.0G Jan  3 10:12 appendonly.aof
-rw-r--r-- 1 redis redis 1.1G Jan  3 10:10 dump.rdb

Ce que cela signifie : Les fichiers AOF et RDB existent et sont volumineux.

Décision : Décidez si vous avez besoin des deux. Sinon, désactivez-en un et récupérez du budget I/O. Si vous gardez les deux, planifiez la capacité et testez les temps de redémarrage.

Tâche 13 : Vérifier les logs du conteneur pour les avertissements de persistance

cr0x@server:~$ docker logs --tail 200 redis | egrep -i 'AOF|fsync|rewrite|RDB|fork|latency|WARNING'
1:C 03 Jan 2026 10:12:05.101 # Background append only file rewriting started by pid 42
1:C 03 Jan 2026 10:12:12.220 # AOF rewrite child asks to stop sending diffs.
1:M 03 Jan 2026 10:12:12.221 # Parent agreed to stop sending diffs. Finalizing...
1:M 03 Jan 2026 10:12:12.980 # Background AOF rewrite finished successfully
1:M 03 Jan 2026 10:12:13.005 # Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

Ce que cela signifie : Redis vous dit explicitement que le disque est occupé et que le fsync est lent.

Décision : Traitez cela comme un incident de stockage, pas un bug applicatif. Allez regarder les I/O au niveau hôte, la contention et le chemin de montage.

Tâche 14 : Mesurer la distribution de latence des commandes Redis (ne devinez pas)

cr0x@server:~$ docker exec -it redis redis-cli --latency-history -i 1
min: 0, max: 87, avg: 2.41 (320 samples) -- 1.00 seconds range

Ce que cela signifie : Vous observez des pics occasionnels à plus de 80 ms. C’est cohérent avec des blocages fsync ou des pauses fork/réécriture.

Décision : Si les pics coïncident avec la réécriture AOF ou la saturation disque, ajustez la persistance et corrigez le stockage. Si les pics coïncident avec le throttling CPU, corrigez les limites CPU.

Tâche 15 : Vérifier que la persistance survit au redémarrage du conteneur (le seul test qui compte)

cr0x@server:~$ docker exec -it redis redis-cli SET durability_test 123
OK
cr0x@server:~$ docker restart redis
redis
cr0x@server:~$ docker exec -it redis redis-cli GET durability_test
"123"

Ce que cela signifie : Votre chemin de persistance et votre config survivent à un redémarrage normal.

Décision : Si cela échoue, vous ne persistez pas où vous pensez, ou votre configuration n’est pas appliquée. Corrigez avant de discuter des réglages.

Tâche 16 : Vérifier si vous utilisez accidentellement overlay2 pour la persistance malgré tout

cr0x@server:~$ docker exec -it redis sh -lc 'mount | egrep " /data |overlay"'
/dev/nvme0n1p2 on /data type ext4 (rw,relatime,errors=remount-ro)
overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/...,upperdir=/var/lib/docker/overlay2/.../diff,workdir=/var/lib/docker/overlay2/.../work)

Ce que cela signifie : Super : /data est un montage ext4 réel, distinct de la racine overlay.

Décision : Si /data apparaît comme overlay, vous avez trouvé la raison du « pourquoi c’est lent ». Déplacez-le vers un volume/bind mount.

Playbook de diagnostic rapide

Quand la latence Redis devient mauvaise après avoir activé la persistance, vous voulez identifier le goulot d’étranglement en minutes, pas après trois réunions et un tableur.
Vérifiez ceci dans l’ordre.

Premièrement : écrivons-nous au mauvais endroit ?

  • Confirmez dir et les noms de fichiers : redis-cli CONFIG GET dir dbfilename appendfilename
  • Confirmez qu’un montage existe : docker inspect ...Mounts et mount | grep /data
  • Si les fichiers de persistance sont sur overlay2, arrêtez-vous. Déplacez-les vers un volume/bind mount, puis retestez.

Deuxièmement : est-ce la latence du stockage ?

  • Cherchez des avertissements Redis sur fsync lent dans les logs.
  • Vérifiez aof_delayed_fsync et s’il augmente pendant les pics.
  • Exécutez iostat -x et regardez w_await, aqu-sz et %util.
  • Si le disque est saturé, trouvez le voisin bruyant : sauvegardes, ingestion de logs, pulls d’images ou autre base sur le même appareil.

Troisièmement : est-ce la pression mémoire/fork/réécriture ?

  • Vérifiez la marge mémoire : INFO memory et les limites mémoire du conteneur.
  • Vérifiez si la réécriture AOF ou le bgsave RDB se corrélent aux pics.
  • Cherchez des OOM kills dans les logs hôte si Redis disparaît pendant des événements de persistance.

Quatrièmement : le throttling CPU aggrave-t-il tout ?

  • Inspectez les quotas et limites CPU.
  • Corrélez les pics de latence avec les métriques de throttling CPU (stats cgroup si disponibles).
  • La persistance Redis n’est pas gratuite ; ne la traitez pas comme un processus en arrière-plan et attendez une latence déterministe.

Trois mini-histoires d’entreprise depuis les tranchées de la durabilité

1) Incident dû à une mauvaise hypothèse : « Les volumes Docker sont toujours persistants »

Une équipe produit de taille moyenne a conteneurisé Redis pour un service de sessions. Ils ont utilisé Docker Compose, mis appendonly yes, et se sont sentis couverts.
Le déploiement « fonctionnait » pendant des semaines. Puis ils ont fait une mise à jour de l’OS hôte et reconstruit la pile.

Après la maintenance, les sessions avaient disparu. L’application a mal récupéré parce qu’elle supposait l’existence des sessions et a essayé de les valider contre des clés manquantes.
Leurs tableaux de bord montraient Redis en marche, CPU ok, mémoire ok. Mais les utilisateurs étaient effectivement déconnectés.

La cause racine n’était pas Redis. C’était l’hypothèse que les données persistaient parce qu’ils avaient activé la persistance.
Ils n’avaient pas de montage de volume. /data vivait dans la couche modifiable du conteneur. Quand ils ont remplacé le conteneur, ils ont remplacé le système de fichiers.

La correction fut ennuyeuse : un volume nommé monté sur /data, plus un test de redémarrage en CI qui écrit une clé, redémarre le conteneur et vérifie sa présence.
Ils ont aussi documenté ce que « persistance » signifie dans leur environnement : persistance sur un chemin hôte spécifique, pas « j’ai activé un flag une fois ».

2) Optimisation qui a mal tourné : « Mettre l’AOF sur stockage réseau pour survivre au nœud »

Une autre entreprise voulait la résilience aux pannes de nœud sans utiliser la réplication Redis (longue histoire, surtout politique).
Quelqu’un a suggéré de monter /data sur un volume réseau pour que n’importe quel nœud puisse le reprendre. Cela sonnait élégant sur une slide.

En test, le débit semblait correct. En production, le p99 de latence a explosé pendant les heures de pointe.
L’équipe app voyait des timeouts occasionnels et accusait Redis. L’équipe plateforme voyait Redis CPU à 20% et disait « ça ne peut pas être Redis ».
Le SRE d’astreinte a vu les avertissements fsync AOF et n’a pas été populaire longtemps.

Le problème : stockage réseau avec une latence fsync incohérente.
Le flush « everysec » a toujours besoin que le backend complète les écritures durables régulièrement ; quand le stockage a subi de la contention, fsync a bloqué plus longtemps.
Redis a fait ce qu’il fallait — il a attendu — tandis que l’app fondait.

La résolution a été d’arrêter de prétendre que la persistance distante est gratuite. Ils ont remis l’AOF sur SSD local, ajouté la réplication pour la résilience,
et gardé le stockage réseau pour des backups RDB périodiques copiés hors bande. La latence s’est immédiatement stabilisée.

3) Pratique ennuyeuse mais correcte qui a sauvé la mise : « Capacité et marge pour la réécriture »

Un service adjacent à la finance utilisait Redis comme magasin d’état rapide. Ils ont activé l’AOF avec everysec et avaient un SLO propre.
L’équipe avait une habitude peu glamour : budgéter mémoire et disque pour les événements de persistance en pire cas, pas pour l’usage moyen.

Ils suivaient trois nombres chaque semaine : taille du dataset, taille de l’AOF, et mémoire de pic pendant la réécriture. Si l’AOF grossissait trop vite, ils ajustaient les seuils de réécriture.
Si la fragmentation mémoire montait, ils planifiaient une fenêtre de redémarrage contrôlée (avec des replicas) plutôt que d’attendre un OOM aléatoire.

Un jour un pattern de trafic a changé — plus d’écritures, plus de churn. L’AOF a grandi, les réécritures sont devenues plus fréquentes.
Sur un système moins discipliné, c’est là que vous obtenez une tempête de réécriture et des pics de latence qui ressemblent à un DDoS interne.

Leur système n’a pas bronché. Ils avaient de la marge. Les réécritures se sont terminées avant que les disques ne saturent, et les pics mémoire induits par le fork sont restés sous les limites.
Le rapport d’incident fut court et profondément inintéressant, ce qui est le compliment le plus élevé en opérations.

Erreurs courantes : symptôme → cause racine → correctif

1) Redis est rapide sans persistance, lent avec AOF

Symptôme : Activer l’AOF fait bondir la latence p99 et chute le débit.

Cause racine : latence fsync et contention de stockage ; souvent aggravé par des volumes réseau ou des disques saturés.

Correctif : Utilisez un volume local SSD, gardez appendfsync everysec, isolez les données Redis des I/O bruyants, et surveillez aof_delayed_fsync.

2) Les données disparaissent après recréation du conteneur

Symptôme : Redémarrer le conteneur conserve parfois les données ; redéployer les perd.

Cause racine : Fichiers de persistance stockés dans la couche modifiable du conteneur (overlay2), pas sur un volume/bind mount.

Correctif : Montez /data sur un volume Docker ou un bind mount ; vérifiez avec docker inspect et un test de redémarrage.

3) Pics de latence périodiques toutes les quelques minutes

Symptôme : Pics qui se corrèlent avec des tâches d’arrière-plan.

Cause racine : snapshots RDB ou réécriture AOF provoquant fork copy-on-write, rafales disque et pression sur le cache.

Correctif : Ajustez le calendrier des snapshots ; tunez les seuils de réécriture AOF ; assurez la marge mémoire ; envisagez de désactiver RDB si l’AOF est principal.

4) Redis se fait OOM-killer pendant la réécriture ou le snapshot

Symptôme : Le conteneur meurt, redémarre, et les logs montrent une activité de persistance autour de l’événement.

Cause racine : Fork + copy-on-write augmente temporairement la mémoire ; limite mémoire du conteneur trop serrée ; fragmentation élevée.

Correctif : Augmenter la marge mémoire ; réduire le dataset ; envisager un maxmemory inférieur à la limite du conteneur ; surveiller le ratio de fragmentation.

5) L’AOF grossit indéfiniment et les redémarrages sont lents

Symptôme : Redémarrage long ; AOF énorme.

Cause racine : Seuils de réécriture AOF trop conservateurs ou réécriture échouant à cause de l’espace disque.

Correctif : Définissez des auto-aof-rewrite-percentage/min-size sensés ; assurez-vous d’avoir de l’espace libre ; vérifiez les logs pour les échecs de réécriture.

6) Redis est « durable » mais perd quand même des données après un crash hôte

Symptôme : Après une perte de courant, l’AOF présente des trous bien que fsync ait été configuré.

Cause racine : La pile de stockage a menti sur les flushs, cache d’écriture volatile, ou comportement de couche de virtualisation.

Correctif : Utilisez un stockage avec des sémantiques de flush vérifiées ; évitez le caching RAID non sûr ; validez les scénarios de panne ; envisagez la réplication et WAIT pour des garanties plus fortes.

7) Activer no-appendfsync-on-rewrite « règle » la latence mais augmente la perte de données

Symptôme : La latence se lisse, mais après un crash pendant la réécriture, plus de données manquent que prévu.

Cause racine : Vous avez explicitement accepté une fenêtre de durabilité plus grande pendant la réécriture.

Correctif : Si la fenêtre de perte est inacceptable, désactivez-le et corrigez le chemin disque et la contention I/O ; ou réduisez la fréquence des réécritures.

Listes de contrôle / plan étape par étape

Étape par étape : obtenir la persistance correcte dans Docker sans tuer les performances

  1. Décidez votre fenêtre de perte.
    Minutes ? Utilisez RDB. Environ une seconde ? Utilisez AOF everysec. « Aucune » ? Préparez-vous à la réplication et à un stockage sérieux.
  2. Montez /data sur un vrai volume.
    Un volume nommé convient. Un bind mount convient. Overlay2 n’est pas acceptable pour ça.
  3. Choisissez une méthode de persistance primaire.
    En avoir deux est valide mais coûte en I/O et mémoire. Si vous gardez les deux, faites-le de façon intentionnelle.
  4. Budgétez la mémoire pour le fork/la réécriture.
    Laissez de la marge. Si vous limitez le conteneur à « taille du dataset plus un sandwich », le sandwich sera supprimé en runtime.
  5. Confirmez le comportement de latence du stockage avec des vérifications réelles.
    Surveillez les avertissements fsync et aof_delayed_fsync. Ne vous fiez pas au seul « c’est un SSD » comme métrique.
  6. Réglez les seuils de réécriture pour éviter les réécritures surprises.
    Vous voulez que les réécritures soient régulières et ennuyeuses, pas rares et catastrophiques.
  7. Test : écrire une clé → redémarrer → lire la clé.
    Intégrez-le en CI ou dans un hook pré-déploiement. Si ce test échoue, tout le reste n’est que théâtre.
  8. Surveillez les bons signaux.
    Latence Redis, stats de persistance, latence disque, utilisation disque, fragmentation mémoire et événements OOM du conteneur.

Checklist : quand vous changez les paramètres de persistance

  • Confirmez la config appliquée (CONFIG GET).
  • Confirmez que le chemin des données est un montage (docker inspect, mount).
  • Confirmez que le disque a de l’espace libre pour réécriture/snapshot.
  • Exécutez un test de charge incluant des écritures et mesurez p95/p99.
  • Simulez un redémarrage et vérifiez la survie de la clé.
  • Enregistrez la nouvelle baseline : aof_delayed_fsync, durée snapshot, durée réécriture.

Checklist : sanity du stockage pour la persistance Redis

  • SSD/NVMe local préféré pour l’AOF.
  • Évitez de partager l’appareil avec de lourdes écritures de logs et des backups.
  • Validez les sémantiques de flush si vous revendiquez la durabilité.
  • Connaissez votre type de système de fichiers et vos options de montage.

FAQ

1) Dois‑je activer RDB et AOF simultanément ?

Seulement si vous avez une stratégie de restauration spécifique qui bénéficie des deux. L’AOF offre une granularité de durabilité meilleure ; RDB offre des snapshots compacts et parfois un démarrage à froid plus rapide.
Utiliser les deux augmente le travail d’arrière-plan et les I/O. Si vous ne savez pas pourquoi vous voulez les deux, vous n’en avez probablement pas besoin.

2) Pourquoi Redis est devenu lent après avoir activé l’AOF ?

L’AOF ajoute une amplification d’écriture et un comportement de flush. Même avec everysec, Redis dépend du chemin de stockage pour compléter les flushs réguliers.
Un fsync lent, des disques saturés ou des volumes réseau à latence incohérente se traduiront directement par de la latence de requête.

3) L’overlay2 de Docker est‑il vraiment si mauvais pour la persistance Redis ?

Overlay2 convient pour les images de conteneurs et les petites écritures. La persistance Redis est intensive en écritures et sensible à la latence.
Overlay2 ajoute du copy-on-write et un surcoût métadonnées. Vous pouvez vous en sortir à faible volume, jusqu’à ce que non. Mettez la persistance sur un montage.

4) Quel est le meilleur réglage appendfsync ?

Pour la plupart des productions : everysec. C’est le compromis pragmatique entre performances et durabilité.
Utilisez always uniquement après avoir validé le stockage et si vous en avez vraiment besoin. Utilisez no quand Redis est un cache jetable et que vous acceptez plus de perte.

5) Puis‑je utiliser tmpfs pour l’AOF pour le rendre rapide ?

Vous pouvez, mais cela va à l’encontre de l’objectif de persistance : si l’hôte perd l’alimentation, tmpfs oublie tout avec enthousiasme.
tmpfs peut servir pour des caches éphémères ou comme zone de staging combinée à une stratégie de réplication/sauvegarde séparée, mais n’appelez pas ça de la durabilité.

6) Ma réécriture AOF provoque des pics de latence. Que dois‑je régler en premier ?

Assurez‑vous d’abord que les données sont sur un chemin disque rapide et isolé. Puis ajustez les seuils de réécriture pour éviter des réécritures fréquentes.
Si la fenêtre de perte le permet, no-appendfsync-on-rewrite yes peut réduire les blocages, mais c’est un compromis conscient de durabilité.

7) Comment savoir si je perds des données à cause de la fenêtre d’une seconde ?

Avec everysec, vous pouvez perdre jusqu’à environ une seconde d’écritures reconnues sur crash, parfois plus si le système est sous forte pression I/O.
Surveillez aof_delayed_fsync et les métriques de stockage ; si les flushs sont retardés, votre fenêtre de perte effective grandit.

8) La persistance Redis est‑elle une sauvegarde ?

Non. La persistance est une récupération après crash pour ce nœud. Les sauvegardes nécessitent des copies séparées, des politiques de rétention et une vérification de restauration.
Considérez la persistance comme « je peux redémarrer sans tout recharger depuis l’amont », pas comme « j’ai une sécurité archivistique ».

9) Et si j’exécute Redis sur Kubernetes — même histoire ?

Même physique, plus d’abstraction. Vous avez toujours besoin d’un volume persistant avec des performances connues, vous avez toujours besoin de marge mémoire pour fork/réécriture,
et vous devez toujours tester le comportement de redémarrage. Kubernetes facilite le déplacement des pods ; il n’accélère pas fsync.

10) De combien d’espace disque ai‑je besoin pour l’AOF ?

Assez pour l’AOF actuel, plus la marge de réécriture (puisque la réécriture écrit un nouveau fichier avant le swap), plus une marge de sécurité.
Si vous êtes serré en disque, les réécritures échouent, l’AOF grossit, les redémarrages ralentissent, et vous vous retrouvez à déboguer l’espace disque au lieu de servir le trafic.

Prochaines étapes pratiques

Si vous exécutez Redis dans Docker et que vous voulez la persistance sans en faire une application disque lente, faites ceci dans l’ordre :

  1. Confirmez que les fichiers de persistance sont sur un vrai montage (volume ou bind mount) et non sur overlay2.
  2. Choisissez votre cible de durabilité : RDB pour une récupération grossière, AOF everysec pour une récupération plus serrée.
  3. Mesurez la douleur du fsync avec INFO persistence de Redis et iostat -x de l’hôte. Ne tunez pas à l’aveugle.
  4. Budgétez une marge mémoire pour que fork/réécriture ne déclenche pas d’OOM.
  5. Exécutez le test de survie au redémarrage comme gate avant tout déploiement touchant le stockage ou la config Redis.

Redis peut être rapide et persistant. Il ne le fera simplement pas à votre place pendant que vous cachez ses fichiers dans un labyrinthe copy-on-write et appelez cela « cloud-native ».

← Précédent
Proxmox LXC Bind-Mount Permission Denied : UID/GID, conteneurs non privilégiés et la correction qui fonctionne vraiment
Suivant →
Erreur critique WooCommerce après mise à jour : restaurer et récupérer en toute sécurité

Laisser un commentaire