Quatre stratégies essentielles pour résoudre les fuites mémoire et les pics dans Redis

Les fuites mémoire et les pics soudains peuvent paralyser les performances de Redis. Ce guide expert propose quatre stratégies essentielles pour gérer et résoudre de manière proactive la consommation mémoire. Apprenez à utiliser les commandes `INFO` et `MEMORY USAGE` pour un diagnostic approfondi, à mettre en œuvre des politiques d'éviction `maxmemory` efficaces, à identifier et à élaguer les clés massives à l'origine d'une croissance inattendue, et à résoudre les problèmes de fragmentation au niveau système grâce à la défragmentation active. Stabilisez les performances de votre cache et assurez la fiabilité de votre magasin de données en mémoire avec ces techniques éprouvées et actionnables.

Quatre stratégies essentielles pour résoudre les fuites mémoire et les pics dans Redis

Redis est un magasin de données en mémoire, donc les problèmes de mémoire apparaissent rapidement. Une petite erreur dans la gestion des TTL, une liste surdimensionnée ou une sauvegarde en arrière-plan sur un hôte sans RAM disponible peuvent se transformer en latence, erreurs d'écriture, évictions, swap, ou un processus Redis tué par le système d'exploitation.

La première habitude utile est d'arrêter d'appeler toute augmentation de mémoire une fuite. Les vraies fuites Redis sont rares. La plupart des incidents sont l'une de ces trois choses : une croissance réelle des données, une fragmentation de l'allocateur ou une surcharge temporaire de copy-on-write lors de la persistance. Ils se ressemblent sur un tableau de bord, mais les correctifs sont complètement différents.

Si used_memory continue d'augmenter, votre application stocke probablement plus de données que prévu. Si used_memory est stable mais que used_memory_rss bondit, examinez la fragmentation, le travail en arrière-plan forké ou le système d'exploitation. Si les deux augmentent lors d'un pic de trafic et ne redescendent jamais, vérifiez les TTL, la politique d'éviction et les grandes clés.

Stratégie 1 : Surveillance détaillée des métriques d'utilisation et de fragmentation

La première étape pour diagnostiquer tout problème de mémoire consiste à établir une base de référence et à comprendre comment Redis rapporte l'utilisation de la mémoire. La commande standard INFO memory fournit des métriques essentielles qui différencient la mémoire utilisée par les données de celle utilisée par le système d'exploitation.

Métriques clés pour le diagnostic

Lorsqu'un pic se produit, regardez immédiatement ces métriques de INFO memory :

  1. used_memory : mémoire allouée par Redis pour les données et les structures internes.
  2. used_memory_dataset : mémoire utilisée par l'ensemble de données réel, hors certains frais généraux.
  3. used_memory_rss : mémoire résidente que le système d'exploitation a attribuée au processus Redis.
  4. mem_fragmentation_ratio : une comparaison approximative du RSS avec la mémoire allouée. Considérez-le comme un indice, pas un verdict.
# Vérifier les statistiques mémoire de base
redis-cli INFO memory

# Exemple de sortie
# used_memory:1073741824 			# 1 Go de données
# used_memory_rss:1509949440 		# ~1,5 Go en RAM
# mem_fragmentation_ratio:1.40625 	# RSS est environ 40% plus élevé que used_memory

Interprétation du ratio de fragmentation

Un ratio proche de 1.0 est généralement sain. Un ratio supérieur à 1.5 mérite une enquête, surtout si le RSS est suffisamment élevé pour menacer l'hôte. Un ratio inférieur à 1.0 ne prouve pas automatiquement un swap ; cela peut arriver en raison de cas limites de mesure, de comptabilité de mémoire partagée ou de très petits ensembles de données. Vérifiez les métriques de swap du système d'exploitation directement avec vmstat, top, sar ou votre système de surveillance.

Si used_memory est stable mais que le RSS augmente lors de BGSAVE ou BGREWRITEAOF, le copy-on-write en est probablement la cause. Le processus enfant écrit un fichier de persistance tandis que le parent continue de gérer les écritures. Les pages modifiées par le parent peuvent devoir être copiées, ce qui augmente temporairement la pression mémoire.

Stratégie 2 : Mise en œuvre de politiques d'éviction robustes

La croissance illimitée est la cause unique la plus fréquente des « fuites » mémoire perçues dans Redis. Si l'instance est utilisée comme cache, elle doit avoir un plafond défini pour l'utilisation de la mémoire, appliqué par la directive maxmemory.

Si maxmemory n'est pas défini, Redis peut continuer à allouer de la mémoire jusqu'à ce que l'hôte soit sous pression. Sur une boîte Redis dédiée, cela peut se terminer par le noyau tuant Redis. Dans un conteneur, le runtime du conteneur peut le tuer plus tôt.

Définition de maxmemory et sélection de la politique

Spécifiez la limite de mémoire maximale dans votre redis.conf ou en utilisant CONFIG SET :

# Définir la mémoire max à 4 Go. Laissez de la marge pour les frais généraux Redis,
# les processus enfants forkés, le cache de pages du système d'exploitation et les autres processus.
CONFIG SET maxmemory 4gb

# Configurer la politique d'éviction
# allkeys-lru : Évincer les clés les moins récemment utilisées dans l'*ensemble* du jeu de données
CONFIG SET maxmemory-policy allkeys-lru
Nom de la politique Description Cas d'utilisation
noeviction Par défaut. Renvoie des erreurs sur les commandes d'écriture lorsque la limite de mémoire est atteinte. Bases de données où aucune perte de données n'est acceptable.
allkeys-lru Évince les clés les moins récemment utilisées, indépendamment de l'expiration. Mise en cache à usage général.
volatile-lru Évince les clés les moins récemment utilisées uniquement parmi celles qui ont une expiration définie. Cas d'utilisation mixtes (données persistées + données de cache).
allkeys-random Évince des clés aléatoires lorsque la limite est atteinte. Magasins de sessions simples ou lorsque le modèle d'accès est imprévisible.

Pour un cache pur, allkeys-lru ou allkeys-lfu est souvent un bon point de départ. Pour une instance Redis mixte où seules certaines clés sont jetables, volatile-lru ou une autre politique volatile-* peut être plus sûr, mais seulement si chaque clé de cache a une expiration. La configuration dangereuse est un cache avec noeviction, aucune discipline TTL et aucune alerte avant que la mémoire ne soit pleine.

Stratégie 3 : Diagnostic et élagage des pics de grandes clés

Parfois, le problème n'est pas le nombre de clés. C'est une clé qui a grandi sans limite : une liste de flux utilisateur qui ne se réduit jamais, un ensemble trié de tous les événements jamais vus, ou un hachage utilisé comme dépotoir pour les champs de session.

Utilisation de redis-cli --bigkeys

L'utilitaire redis-cli --bigkeys analyse l'espace de clés et signale les grandes clés par type et nombre d'éléments. Il ne mesure pas la taille exacte en octets et peut ajouter de la charge sur une instance de production occupée, alors exécutez-le avec précaution ou contre une réplique si possible.

# Exécuter l'analyse des grandes clés
redis-cli --bigkeys

# Exemple de sortie (identification d'une liste massive)
---------- Résumé ----------
...
[5] Plus grande liste trouvée 'user:1001:feed' avec 859387 éléments

Utilisation de MEMORY USAGE (Redis 4.0+)

Pour déterminer la taille précise en octets d'une clé suspecte, utilisez la commande MEMORY USAGE. C'est essentiel pour un diagnostic approfondi.

# Vérifier l'utilisation mémoire d'une clé spécifique (en octets)
redis-cli MEMORY USAGE user:1001:feed

# Sortie : (par exemple) 84329014

Si vous identifiez de grandes clés, examinez le chemin d'écriture. Les correctifs courants consistent à réduire les listes avec LTRIM, à faire expirer les structures transitoires, à diviser les très grands hachages ou ensembles triés en partitions de clés plus petites, et à remplacer les lectures « tout charger » par un accès paginé tel que HSCAN, SSCAN ou ZSCAN. Le vrai correctif réside généralement dans le comportement de l'application, pas dans un bouton Redis.

Stratégie 4 : Gestion de la fragmentation mémoire et du copy-on-write

Une fragmentation élevée ou des pics soudains de RSS sont souvent confondus avec des fuites de données. Ces problèmes sont liés à l'allocation mémoire, au renouvellement d'objets et à la persistance basée sur fork.

Défragmentation active

La défragmentation active peut aider Redis à récupérer l'espace perdu de l'allocateur pendant que le serveur continue de fonctionner. Elle est utile pour les charges de travail qui créent et suppriment de nombreuses valeurs de tailles différentes. Elle utilise également du CPU, alors activez-la délibérément et surveillez la latence après le changement.

Activez-la et configurez-la dans redis.conf :

# Activer la défragmentation active
activedefrag yes

# Les seuils inférieur et supérieur sont des valeurs de configuration de type pourcentage.
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100

Réduction de la surcharge du copy-on-write

Lorsque Redis fork un processus enfant pour les snapshots RDB ou les réécritures AOF, le système d'exploitation utilise l'optimisation CoW. Si le processus parent effectue des écritures lourdes pendant que le processus enfant est actif, chaque page écrite doit être dupliquée, ce qui fait temporairement grimper used_memory_rss. Ce pic peut facilement doubler l'empreinte mémoire de Redis.

Étapes d'atténuation :

  1. Planifiez la persistance pendant les périodes de faible trafic.
  2. Laissez une marge mémoire au-dessus de maxmemory pour les frais généraux de l'allocateur, les clients, les tampons de réplication et les processus enfants forkés. La marge appropriée dépend de la taille de l'ensemble de données et du taux d'écriture ; mesurez-la lors d'un BGSAVE ou BGREWRITEAOF réel.
  3. Évitez de chevaucher les travaux d'arrière-plan lourds tels que les snapshots, les réécritures AOF, les sauvegardes et les analyses au niveau de l'hôte.
  4. Réduisez le renouvellement des écritures pendant la persistance si un travail par lots provoque une croissance du copy-on-write.

N'utilisez pas les variables d'environnement de l'allocateur comme première réponse. Redis est généralement construit avec jemalloc, et changer le comportement de l'allocateur sans test peut créer une nouvelle latence ou un nouveau comportement mémoire. Si la fragmentation reste sévère après la défragmentation active et les correctifs de charge de travail, testez les modifications sur une instance de staging ou une réplique avant de toucher à la production.

Un flux d'incident pratique

Lorsque la mémoire augmente, rassemblez les faits avant de redémarrer Redis. Un redémarrage peut cacher les preuves.

Exécutez :

redis-cli INFO memory
redis-cli INFO persistence
redis-cli DBSIZE
redis-cli --bigkeys

Demandez ensuite ce qui a changé. Un déploiement a-t-il supprimé les TTL ? Un consommateur de file d'attente s'est-il arrêté, provoquant la croissance des listes ? Un nouveau travail de reporting a-t-il exécuté HGETALL sur d'énormes hachages ? Une réécriture AOF a-t-elle commencé pendant le pic de trafic ? La limite de mémoire du conteneur a-t-elle changé ?

Les meilleurs correctifs mémoire Redis sont généralement simples : définir un maxmemory réaliste, choisir une politique d'éviction adaptée à la charge de travail, donner un TTL à chaque clé de cache, diviser les structures illimitées, empêcher la persistance de s'exécuter sans marge mémoire, et alerter sur les tendances mémoire avant que l'instance n'atteigne le gouffre.