Pourquoi Redis utilise-t-il beaucoup de CPU ? Techniques de débogage et d'optimisation

Enquêtez sur une utilisation soudaine et élevée du CPU dans Redis, un magasin de données en mémoire critique. Ce guide détaille comment déboguer la charge à l'aide des commandes `SLOWLOG` et `INFO` pour identifier les opérations inefficaces comme `KEYS *` ou les suppressions de grandes clés. Apprenez des techniques d'optimisation pratiques, notamment le passage à `UNLINK` asynchrone, l'utilisation du pipelining et le réglage des paramètres de persistance, pour réduire immédiatement la charge du serveur et restaurer des performances Redis optimales.

Pourquoi Redis utilise-t-il beaucoup de CPU ? Techniques de débogage et d'optimisation

Un CPU élevé dans Redis signifie généralement l'une des trois choses suivantes : Redis effectue trop de travail de commande sur son chemin d'exécution principal, un travail en arrière-plan comme la persistance ajoute de la pression, ou les clients envoient du trafic d'une manière que Redis ne peut pas traiter efficacement. La solution dépend de laquelle est vraie.

Ne commencez pas par redémarrer Redis, sauf si le service est déjà en train de s'effondrer. Un redémarrage peut effacer le symptôme et effacer les preuves. Commencez par capturer la latence des commandes, la répartition des commandes, le nombre de clients, l'état de la persistance et le CPU de l'hôte. Ces faits vous indiquent si vous avez une mauvaise commande, un mauvais modèle de trafic, un cœur unique surchargé ou un hôte bruyant.

Comprendre l'architecture de Redis et la charge CPU

Redis est souvent décrit comme monothread, ce qui est surtout vrai pour l'exécution des commandes, mais Redis moderne peut également utiliser des threads d'arrière-plan et des threads d'E/S optionnels. Le point pratique reste le même : une commande qui prend trop de temps peut retarder d'autres clients, et un cœur saturé peut suffire à créer une latence visible même lorsque la machine a du CPU inactif ailleurs.

Facteurs clés influençant la charge CPU de Redis

Les causes courantes sont les commandes coûteuses, les grandes valeurs, les scripts Lua, trop de petites commandes envoyées un aller-retour à la fois, un renouvellement important de connexions, l'activité de persistance et la pression mémoire qui oblige le noyau à travailler plus dur que Redis ne le prévoit.

Débogage d'une utilisation élevée du CPU

Avant d'optimiser, vous devez identifier avec précision la source de la charge. Les outils de surveillance et les commandes Redis intégrées sont essentiels pour le diagnostic.

1. Utilisation des commandes INFO et LATENCY

La commande INFO fournit un instantané de l'état du serveur. Concentrez-vous sur la section CPU et les statistiques des commandes.

redis-cli INFO cpu

Regardez le taux de changement, pas seulement les valeurs absolues. used_cpu_user qui augmente rapidement indique souvent un traitement de commande. used_cpu_sys qui augmente rapidement peut indiquer un travail du noyau comme la mise en réseau, la gestion de la mémoire ou une activité liée au disque.

Les outils de latence montrent les classes d'événements que Redis a observées :

redis-cli LATENCY LATEST
redis-cli LATENCY DOCTOR

2. Identification des commandes lentes avec SLOWLOG

Le journal lent de Redis enregistre les commandes qui dépassent un temps d'exécution spécifié. C'est votre outil le plus direct pour trouver les opérations peu performantes.

Le journal lent de Redis enregistre les commandes dont le temps d'exécution dépasse un seuil. Il n'inclut pas le temps réseau ni le temps d'attente dans le pool de clients, il est donc préférable de l'utiliser en conjonction avec les métriques de latence de l'application.

Exemple de configuration :

slowlog-log-slower-than 1000
slowlog-max-len 1024

Récupération du journal :

redis-cli SLOWLOG GET 10

Examinez le nom de la commande, les noms des clés et la durée. Si KEYS, un grand HGETALL, un énorme SMEMBERS, de larges plages d'ensembles triés ou des scripts Lua dominent le journal, le problème CPU est probablement dû à l'application.

3. Surveillance de l'activité réseau et des clients

MONITOR est tentant lors d'un incident, mais il est coûteux sur un serveur occupé. Préférez INFO commandstats, INFO clients, le journal lent, les métriques de la bibliothèque client et l'échantillonnage à partir d'une réplique si vous en avez une.

Commandes utiles :

redis-cli INFO commandstats
redis-cli INFO clients
redis-cli CLIENT LIST

Si le volume de commandes a doublé après un déploiement, vous pouvez le voir dans cmdstat_get, cmdstat_hgetall ou des compteurs similaires. Si les clients se connectent et se déconnectent constamment, corrigez le pooling avant de régler Redis.

Causes courantes et stratégies d'optimisation

Une fois que vous avez identifié les commandes ou processus problématiques, appliquez des techniques d'optimisation ciblées.

1. Élimination des commandes bloquantes

Les gains les plus rapides proviennent généralement de la suppression des commandes qui forcent Redis à parcourir un vaste espace de clés ou à sérialiser une valeur énorme.

Commande inefficace Pourquoi elle provoque un CPU élevé Optimisation / Alternative
KEYS * Parcourt tout l'espace de clés. O(N). Utilisez SCAN de manière itérative ou restructurez l'accès aux données.
FLUSHALL / FLUSHDB Supprime chaque clé sauf si le mode asynchrone est utilisé. Utilisez une suppression minutieuse et ciblée, UNLINK, ou un vidage asynchrone uniquement lorsque cela est approprié.
HGETALL, SMEMBERS (sur de très grands ensembles) Récupère toute la structure en mémoire et la sérialise. Utilisez HSCAN, SSCAN, ou décomposez les grandes structures en clés plus petites.

Utilisez UNLINK au lieu de DEL pour les très grandes clés. DEL libère la mémoire de manière synchrone. UNLINK supprime la clé de l'espace de clés et libère la mémoire de manière asynchrone, ce qui réduit généralement la latence visible lors des grandes suppressions.

# Au lieu de DEL large_key
UNLINK large_key

2. Optimisation de la persistance (RDB et AOF)

Les instantanés RDB et les réécritures AOF utilisent des processus enfants et peuvent toujours affecter le parent via le coût du fork, la mémoire copy-on-write, la bande passante disque et la contention CPU.

  • Instantanés RDB : Si vous sauvegardez fréquemment (par exemple, toutes les minutes), les appels fork() répétés provoqueront des pics de CPU récurrents. Réduisez la fréquence des sauvegardes automatiques.
  • Réécriture AOF : La réécriture AOF (BGREWRITEAOF) est également gourmande en ressources. Redis tente d'optimiser cela en effectuant un minimum d'E/S, mais l'utilisation du CPU augmentera pendant le processus.

Si la persistance coïncide avec les pics de CPU, vérifiez INFO persistence et les métriques du disque hôte. Vous pouvez réduire la fréquence RDB, planifier les sauvegardes lourdes loin des pics de trafic, laisser plus de marge mémoire ou améliorer le stockage. Mettre en pause la persistance peut réduire la charge, mais cela augmente également le risque de perte de données, cela doit donc être une décision opérationnelle délibérée.

3. Gestion de la fragmentation mémoire et du swapping

Bien que les problèmes de mémoire soient souvent associés à une utilisation élevée de la mémoire, une fragmentation mémoire sévère ou, pire, le système d'exploitation qui commence à échanger les données Redis sur le disque (thrashing) augmentera considérablement l'utilisation du CPU car le noyau lutte pour gérer la mémoire.

  • Vérification du swapping : Utilisez les outils du système d'exploitation (vmstat, top) pour vérifier si le système échange activement des pages mémoire appartenant au processus Redis.
  • Ratio de fragmentation mémoire : Vérifiez mem_fragmentation_ratio dans INFO memory. Un ratio élevé est un indice que le comportement de l'allocateur peut gaspiller de la mémoire, mais confirmez avec RSS, la taille du jeu de données et les métriques de mémoire de l'hôte.

Si le swapping se produit, réduisez le jeu de données, abaissez maxmemory, déplacez le travail de l'hôte ou ajoutez de la mémoire. Redis n'est pas conçu pour bien fonctionner lorsque son jeu de données actif est paginé sur le disque.

4. Optimisation réseau et pipelining

Si la charge CPU suit un nombre élevé de petites commandes, le problème peut être la surcharge des commandes et le renouvellement réseau plutôt qu'une commande manifestement lente.

Le pipelining permet à un client d'envoyer plusieurs commandes sans attendre une réponse après chacune. Il réduit les allers-retours et peut améliorer le débit pour les écritures ou lectures en masse. Gardez les lots de pipeline limités ; un pipeline avec des milliers de commandes lourdes peut créer son propre pic de latence.

Meilleures pratiques pour des performances durables

Pour éviter de futurs pics de CPU, adoptez ces meilleures pratiques architecturales et de configuration :

  1. Utilisez UNLINK pour les clés qui peuvent être grandes.
  2. Remplacez KEYS par SCAN, et remplacez les lectures complètes de collections par des lectures basées sur un curseur.
  3. Suivez INFO commandstats après les déploiements pour qu'un nouveau modèle de commande ne vous surprenne pas.
  4. Réglez la persistance en tenant compte de l'espace disque et de la marge mémoire réels.
  5. Si une instance Redis est légitimement saturée après les corrections de commandes, répartissez la charge de travail avec Redis Cluster, le sharding côté client, des instances de cache/session séparées ou une instance plus grande avec de meilleures performances monocœur.

Une liste de contrôle rapide pour les incidents

Pendant un pic, exécutez :

redis-cli INFO cpu
redis-cli INFO commandstats
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli SLOWLOG GET 20
redis-cli LATENCY LATEST

Ensuite, alignez ces résultats avec les déploiements d'applications, les tâches cron, les changements de trafic, les événements de persistance et les métriques de l'hôte. Un CPU élevé dans Redis est généralement réparable, mais la solution est spécifique : supprimez la commande coûteuse, regroupez le client bavard, arrêtez le renouvellement de connexion, donnez de l'espace à la persistance pour travailler, ou répartissez la charge de travail lorsqu'une seule instance est vraiment à sa limite.