Les 5 principaux goulots d'étranglement de performance de Redis et comment les résoudre

Libérez le plein potentiel de performance de vos déploiements Redis grâce à ce guide essentiel sur les goulots d'étranglement courants. Apprenez à identifier et à résoudre des problèmes tels que les commandes O(N) lentes, les allers-retours réseau excessifs, la pression mémoire et les politiques d'éviction inefficaces, les surcoûts de persistance et les opérations gourmandes en CPU. Cet article fournit des étapes concrètes, des exemples pratiques et des meilleures pratiques, allant de l'exploitation du pipelining et de `SCAN` à l'optimisation des structures de données et de la persistance, garantissant que votre instance Redis reste rapide et fiable pour tous vos besoins de mise en cache, de messagerie et de stockage de données.

66 vues

Les 5 principaux goulots d'étranglement de performance de Redis et comment les corriger

Redis est un magasin de structures de données en mémoire incroyablement rapide, largement utilisé comme cache, base de données et courtier de messages. Sa nature mono-thread et sa gestion efficace des données contribuent à ses performances impressionnantes. Cependant, comme tout outil puissant, Redis peut souffrir de goulots d'étranglement de performance s'il n'est pas configuré ou utilisé correctement. Comprendre ces pièges courants et savoir comment les aborder est crucial pour maintenir une application réactive et fiable.

Cet article explore les cinq principaux goulots d'étranglement de performance rencontrés dans les environnements Redis. Pour chaque goulot d'étranglement, nous expliquerons la cause sous-jacente, montrerons comment l'identifier et fournirons des étapes concrètes, des exemples de code et les meilleures pratiques pour résoudre le problème immédiatement. À la fin de ce guide, vous aurez une compréhension complète de la manière de diagnostiquer et de corriger les problèmes de performance Redis les plus courants, garantissant que vos applications tirent pleinement parti de Redis.

1. Commandes lentes et opérations O(N)

Redis est connu pour ses opérations O(1) ultra-rapides, mais de nombreuses commandes, en particulier celles qui opèrent sur des structures de données entières, peuvent avoir une complexité O(N) (où N est le nombre d'éléments). Lorsque N est grand, ces opérations peuvent bloquer le serveur Redis pendant des durées significatives, entraînant une latence accrue pour toutes les autres commandes entrantes.

Coupables courants :
* KEYS : Itère sur toutes les clés de la base de données. Extrêmement dangereux en production.
* FLUSHALL/FLUSHDB : Efface toute la base de données (ou la base de données actuelle).
* HGETALL, SMEMBERS, LRANGE : Lorsqu'elles sont utilisées sur des hachages, des ensembles ou des listes très volumineux, respectivement.
* SORT : Peut être très intensif en CPU sur de grandes listes.
* Scripts Lua qui itèrent sur de grandes collections.

Comment identifier :

  • SLOWLOG GET <count> : Cette commande récupère les entrées du journal des commandes lentes, qui enregistre les commandes dont le temps d'exécution a dépassé un seuil configurable (slowlog-log-slower-than).
  • LATENCY DOCTOR : Fournit une analyse des événements de latence de Redis, y compris ceux causés par des commandes lentes.
  • Surveillance : Surveillez les métriques redis_commands_latency_microseconds_total ou similaires via votre système de surveillance.

Comment corriger :

  • Éviter KEYS en production : Utilisez SCAN à la place. SCAN est un itérateur qui renvoie un petit nombre de clés à la fois, permettant à Redis de traiter d'autres requêtes entre les itérations.
    bash # Exemple : Itération avec SCAN redis-cli SCAN 0 MATCH user:* COUNT 100
  • Optimiser les structures de données : Au lieu de stocker un très grand hachage/ensemble/liste, envisagez de le diviser en morceaux plus petits et plus gérables. Par exemple, si vous avez un hachage user:100:profile avec 100 000 champs, le diviser en user:100:contact_info, user:100:preferences, etc., pourrait être plus efficace si vous n'avez besoin que de parties du profil à la fois.
  • Utiliser les requêtes par plage judicieusement : Pour LRANGE, évitez de récupérer la liste entière. Récupérez des morceaux plus petits ou utilisez TRIM pour les listes de taille fixe.
  • Utiliser UNLINK au lieu de DEL : Pour supprimer de grandes clés, UNLINK effectue la récupération réelle de la mémoire dans un thread d'arrière-plan non bloquant, retournant immédiatement.
    bash # Supprimer une grande clé de manière asynchrone UNLINK ma_grande_cle
  • Optimiser les scripts Lua : Assurez-vous que les scripts sont légers et évitez d'itérer sur de grandes collections. Si une logique complexe est nécessaire, envisagez de décharger une partie du traitement sur le client ou des services externes.

2. Latence réseau et allers-retours excessifs

Même avec la vitesse incroyable de Redis, le temps d'aller-retour (RTT) entre votre application et le serveur Redis peut devenir un goulot d'étranglement important. L'envoi de nombreuses petites commandes individuelles entraîne une pénalité de RTT pour chacune, même si le temps de traitement Redis est minime.

Comment identifier :

  • Latence globale élevée de l'application : Si les commandes Redis elles-mêmes sont rapides mais que le temps total de l'opération est élevé.
  • Surveillance réseau : Des outils comme ping et traceroute peuvent montrer le RTT, mais la surveillance au niveau de l'application est meilleure.
  • Section clients de INFO Redis : Peut montrer les clients connectés, mais n'indique pas directement les problèmes de RTT.

Comment corriger :

  • Pipelining (Pipeline) : C'est la solution la plus efficace. Le pipelining permet à votre client d'envoyer plusieurs commandes à Redis dans un seul paquet TCP sans attendre de réponse pour chacune. Redis les traite séquentiellement et renvoie toutes les réponses dans une seule réponse.
    ```python
    # Exemple de pipelining avec le client Python Redis
    import redis
    r = redis.Redis(host='localhost', port=6379, db=0)

    pipe = r.pipeline()
    pipe.set('cle1', 'valeur1')
    pipe.set('cle2', 'valeur2')
    pipe.get('cle1')
    pipe.get('cle2')
    results = pipe.execute()
    print(results) # [True, True, b'valeur1', b'valeur2']
    `` * **Transactions (MULTI/EXEC)** : Similaire au pipelining, mais garantit l'atomicité (toutes les commandes sont exécutées ou aucune ne l'est). Bien queMULTI/EXEC` effectue un pipelining des commandes par nature, son objectif principal est l'atomicité. Pour de purs gains de performance, le pipelining de base est suffisant.
    * Scripting Lua : Pour les opérations multi-commandes complexes qui nécessitent une logique intermédiaire ou une exécution conditionnelle, les scripts Lua s'exécutent directement sur le serveur Redis. Cela élimine plusieurs RTT en regroupant toute une séquence d'opérations dans une seule exécution côté serveur.

3. Pression mémoire et politiques d'éviction

Redis est une base de données en mémoire. S'il manque de mémoire physique, les performances se dégraderont considérablement. Le système d'exploitation pourrait commencer à effectuer du swap sur disque, entraînant des latences extrêmement élevées. Si Redis est configuré avec une politique d'éviction, il commencera à supprimer des clés lorsque maxmemory est atteint, ce qui consomme également des cycles CPU.

Comment identifier :

  • INFO memory : Vérifiez used_memory, used_memory_rss et maxmemory. Recherchez maxmemory_policy.
  • Taux d'éviction élevés : Si le compteur evicted_keys augmente rapidement.
  • Surveillance au niveau du système : Surveillez l'utilisation élevée du swap ou le manque de RAM disponible sur l'hôte Redis.
  • Erreurs OOM (Out Of Memory) : Dans les journaux ou les réponses des clients.

Comment corriger :

  • Définir maxmemory et maxmemory-policy : Configurez une limite maxmemory judicieuse dans redis.conf pour éviter les erreurs OOM et spécifiez une maxmemory-policy appropriée (par exemple, allkeys-lru, volatile-lru, noeviction). noeviction n'est généralement pas recommandé pour les caches, car il provoque des erreurs d'écriture lorsque la mémoire est pleine.
    ini # redis.conf maxmemory 2gb maxmemory-policy allkeys-lru
  • Définir le TTL (Time-To-Live) sur les clés : Assurez-vous que les données transitoires expirent automatiquement. C'est fondamental pour gérer la mémoire, en particulier dans les scénarios de mise en cache.
    bash SET mykey "hello" EX 3600 # Expire dans 1 heure
  • Optimiser les structures de données : Utilisez les types de données efficaces en mémoire de Redis (par exemple, les hachages encodés en ziplist, les ensembles/ensembles triés en intset) lorsque cela est possible. Les petits hachages, listes et ensembles peuvent être stockés de manière plus compacte.
  • Mettre à l'échelle (Scale up) : Augmentez la RAM de votre serveur Redis.
  • Mettre à l'échelle horizontalement (Sharding) : Distribuez vos données sur plusieurs instances Redis (maîtres) en utilisant le sharding côté client ou Redis Cluster.

4. Surcharges de persistance (RDB/AOF)

Redis offre des options de persistance : instantanés RDB et fichier AOF (Append Only File). Bien que cruciales pour la durabilité des données, ces opérations peuvent introduire une surcharge de performance, en particulier sur les systèmes avec des E/S disque lentes ou lorsqu'elles ne sont pas correctement configurées.

Comment identifier :

  • INFO persistence : Vérifiez rdb_last_save_time, aof_current_size, aof_last_bgrewrite_status, aof_rewrite_in_progress, rdb_bgsave_in_progress.
  • E/S disque élevées : Outils de surveillance montrant des pics d'utilisation du disque pendant les événements de persistance.
  • Blocage de BGSAVE ou BGREWRITEAOF : Temps de fork longs, en particulier sur de grands ensembles de données, peuvent bloquer temporairement Redis (bien que moins courant avec les noyaux Linux modernes).

Comment corriger :

  • Ajuster appendfsync pour AOF : Ceci contrôle la fréquence à laquelle l'AOF est synchronisé sur le disque.
    • appendfsync always : Le plus sûr mais le plus lent (synchronise à chaque écriture).
    • appendfsync everysec : Bon équilibre entre sécurité et performance (synchronise toutes les secondes, par défaut).
    • appendfsync no : Le plus rapide mais le moins sûr (le système d'exploitation décide quand synchroniser). Choisissez everysec pour la plupart des environnements de production.
      ```ini

    redis.conf

    appendfsync everysec
    ```

  • Optimiser les points save pour RDB : Configurez les règles save (save <secondes> <changements>) pour éviter des instantanés trop fréquents ou trop espacés. Souvent, une ou deux règles suffisent.
  • Utiliser un disque dédié : Si possible, placez les fichiers AOF et RDB sur un SSD rapide et séparé pour minimiser la contention des E/S.
  • Décharger la persistance vers les réplicas : Configurez un réplica et désactivez la persistance sur le primaire, permettant au réplica de gérer les instantanés RDB ou les réécritures AOF sans impacter les performances du maître. Cela nécessite un examen attentif des scénarios de perte de données.
  • vm.overcommit_memory = 1 : Assurez-vous que ce paramètre du noyau Linux est défini sur 1. Cela empêche BGSAVE ou BGREWRITEAOF d'échouer en raison de problèmes de surallocation de mémoire lors de la duplication (fork) d'un grand processus Redis.

5. Nature mono-thread et opérations liées au CPU

Redis s'exécute principalement sur un seul thread (pour le traitement des commandes). Bien que cela simplifie le verrouillage et réduise la surcharge de changement de contexte, cela signifie également que toute commande longue ou script Lua bloquera toutes les autres requêtes client. Si l'utilisation du CPU de votre serveur Redis est constamment élevée, c'est un indicateur fort d'opérations liées au CPU.

Comment identifier :

  • Utilisation élevée du CPU : La surveillance au niveau du serveur montre que le processus Redis consomme 100 % d'un cœur de CPU.
  • Latence accrue : INFO commandstats montre des commandes spécifiques avec une latence moyenne anormalement élevée.
  • SLOWLOG : Mettra également en évidence les commandes gourmandes en CPU.

Comment corriger :

  • Diviser les grandes opérations : Comme discuté dans la section 1, évitez les commandes O(N) sur de grands ensembles de données. Si vous devez traiter de grandes quantités de données, utilisez SCAN et traitez les morceaux côté client, ou distribuez le travail.
  • Optimiser les scripts Lua : Assurez-vous que vos scripts Lua sont hautement optimisés et ne contiennent pas de boucles longues ou de calculs complexes sur de grandes structures de données. N'oubliez pas qu'un script Lua s'exécute atomiquement et bloque le serveur jusqu'à son achèvement.
  • Réplicas de lecture : Déchargez les opérations à forte intensité de lecture vers un ou plusieurs réplicas de lecture. Cela répartit la charge de lecture, permettant au maître de se concentrer sur les écritures et les lectures critiques.
  • Sharding (Redis Cluster) : Pour un débit extrêmement élevé ou de grands ensembles de données qui dépassent la capacité d'une seule instance, segmentez vos données sur plusieurs instances maîtres Redis à l'aide de Redis Cluster. Cela répartit la charge CPU et mémoire.
  • client-output-buffer-limit : Des tampons de sortie client mal configurés (par exemple, pour les clients pub/sub) peuvent amener Redis à mettre en mémoire tampon de grandes quantités de données pour un client lent, consommant de la mémoire et du CPU. Ajustez ces limites pour éviter l'épuisement des ressources dû aux clients lents.

Conclusion

L'optimisation des performances de Redis est un processus continu qui implique une surveillance attentive, la compréhension des modèles d'accès de votre application et une configuration proactive. En traitant ces cinq goulots d'étranglement courants — commandes lentes, latence réseau, pression mémoire, surcharges de persistance et opérations liées au CPU — vous pouvez améliorer considérablement la réactivité et la stabilité de votre déploiement Redis.

Utilisez régulièrement des outils tels que les commandes SLOWLOG, LATENCY DOCTOR et INFO. Combinez cela avec une surveillance robuste au niveau du système du CPU, de la mémoire et des E/S disque. N'oubliez pas qu'une instance Redis performante est l'épine dorsale de nombreuses applications hautes performances, et prendre le temps de la régler correctement apportera des avantages substantiels à l'ensemble de votre système.