Dépannage des goulots d'étranglement courants des performances Elasticsearch
Un workflow pratique pour trouver les goulots d'étranglement des performances Elasticsearch dans l'indexation, la recherche, le tas, le stockage et la conception des shards.
Dépannage des goulots d'étranglement courants des performances Elasticsearch
Le dépannage des goulots d'étranglement des performances Elasticsearch fonctionne mieux lorsque vous résistez à la première théorie facile. Un tableau de bord lent peut être dû à une mauvaise requête, mais il peut aussi s'agir d'un shard chaud, d'un disque saturé, d'un problème de tas, d'une erreur de mapping ou d'un processus de récupération en compétition pour les E/S. Commencez par des preuves, puis réduisez le champ d'investigation.
Je divise généralement la question en trois parties : qu'est-ce qui est lent, où est-ce lent et qu'est-ce qui a changé. « Elasticsearch est lent » n'est pas exploitable. « La latence de recherche pour logs-prod-* a doublé après le changement de mapping d'hier, principalement sur deux nœuds de données » vous donne une piste de travail.
Diagnostic des problèmes de performances
Avant de plonger dans des solutions spécifiques, il est essentiel de disposer d'outils et de méthodes pour diagnostiquer les problèmes de performances. Elasticsearch fournit plusieurs API et métriques qui sont inestimables pour ce processus.
Outils et métriques clés :
- API Cluster Health (
_cluster/health) : Fournit un aperçu de l'état du cluster (vert, jaune, rouge), du nombre de nœuds, de shards et de tâches en attente. Un nombre élevé de tâches en attente peut indiquer des problèmes d'indexation ou de récupération. - API Node Stats (
_nodes/stats) : Offre des statistiques détaillées pour chaque nœud, y compris l'utilisation du CPU, la mémoire, les E/S disque, le trafic réseau et l'utilisation du tas JVM. Ceci est essentiel pour identifier les nœuds à court de ressources. - API Index Stats (
_stats) : Fournit des statistiques pour des index individuels, telles que les taux d'indexation, les taux de recherche et l'utilisation du cache. Cela aide à identifier les index problématiques. - Slow Log : Elasticsearch peut enregistrer les requêtes d'indexation et de recherche lentes. Les seuils du slow log sont des paramètres d'index, vous pouvez donc les appliquer à un seul index bruyant au lieu de transformer tout le cluster en générateur de logs.
- Indexing Slow Log : Utile lorsque les écritures en masse s'arrêtent ou que la latence d'ingestion augmente.
- Search Slow Log : Utile lorsque vous avez besoin du modèle de requête réel, pas seulement d'un graphique de latence.
- Outils de surveillance : Des solutions comme l'interface de surveillance de Kibana, Prometheus avec l'exportateur Elasticsearch, ou des outils APM commerciaux fournissent des tableaux de bord et des données historiques pour une analyse plus approfondie.
Goulots d'étranglement courants et solutions
1. Indexation lente
Une indexation lente peut être causée par divers facteurs, notamment la latence réseau, les goulots d'étranglement des E/S disque, des ressources insuffisantes, un mapping inefficace ou une utilisation sous-optimale de l'API Bulk.
Causes et solutions :
Saturation des E/S disque : Elasticsearch dépend fortement d'E/S disque rapides pour l'indexation. Les SSD sont fortement recommandés.
- Diagnostic : Surveillez les IOPS de lecture/écriture disque et le débit à l'aide de
_nodes/statsou d'outils au niveau du système d'exploitation. Recherchez des profondeurs de file d'attente élevées. - Solution : Passez à un stockage plus rapide (SSD), distribuez les shards sur plus de nœuds ou optimisez votre stratégie de sharding pour réduire les E/S par nœud.
- Diagnostic : Surveillez les IOPS de lecture/écriture disque et le débit à l'aide de
Pression sur le tas JVM : Si le tas JVM est constamment sous pression, le garbage collection peut devenir un goulot d'étranglement important, ralentissant toutes les opérations, y compris l'indexation.
- Diagnostic : Surveillez l'utilisation du tas JVM dans Kibana Monitoring ou
_nodes/stats. Une utilisation élevée du tas et des pauses de garbage collection fréquentes et longues sont des signaux d'alarme. - Solution : Augmentez la taille du tas JVM (mais pas au-delà de 50 % de la RAM système et sans dépasser 30,5 Go), optimisez les mappings pour réduire la taille des documents ou ajoutez plus de nœuds pour distribuer la charge.
- Diagnostic : Surveillez l'utilisation du tas JVM dans Kibana Monitoring ou
Mapping inefficace : Des mappings trop complexes, un mapping dynamique avec la création de nombreux nouveaux champs ou des types de données incorrects peuvent augmenter la surcharge d'indexation.
- Diagnostic : Analysez les mappings d'index (API
_mapping). Recherchez les objets imbriqués, un grand nombre de champs ou des champs indexés inutilement. - Solution : Définissez des mappings explicites avec des types de données appropriés. Utilisez
dynamic: falseoudynamic: strictlorsque cela est applicable. Évitez les structures profondément imbriquées si elles ne sont pas essentielles.
- Diagnostic : Analysez les mappings d'index (API
Latence réseau : Une latence élevée entre les nœuds ou entre les clients et le cluster peut ralentir les requêtes d'indexation en masse.
- Diagnostic : Mesurez la latence réseau entre vos clients/nœuds. Analysez les temps de réponse de l'API Bulk.
- Solution : Gardez les nœuds du cluster sur un réseau privé à faible latence, placez les clients Bulk près du cluster lorsque cela est possible et réduisez le trafic inter-régions inutile. Les paramètres du cache de requête ne résoudront pas la latence réseau.
Utilisation sous-optimale de l'API Bulk : L'envoi de requêtes individuelles au lieu d'utiliser des requêtes en masse, ou l'envoi de requêtes en masse excessivement grandes/petites, peut être inefficace.
- Diagnostic : Surveillez le débit de votre indexation en masse. Analysez la taille de vos requêtes en masse.
- Solution : Utilisez l'API Bulk pour toutes les opérations d'indexation. Expérimentez avec la taille du lot (généralement 5 à 15 Mo par requête Bulk est un bon point de départ) pour trouver l'équilibre optimal entre débit et latence. Assurez-vous que vos requêtes Bulk sont correctement regroupées.
Durabilité du translog : Le paramètre
index.translog.durabilitycontrôle la fréquence à laquelle le journal de transactions est vidé sur le disque.request(par défaut) est plus sûr mais peut avoir un impact sur les performances par rapport àasync.- Diagnostic : Il s'agit d'un paramètre de configuration.
- Solution : Pour un débit d'indexation maximal, envisagez la durabilité
async. Cependant, soyez conscient que cela augmente le risque de perte de données en cas de crash d'un nœud entre les vidages.
2. Requêtes lentes
Les performances des requêtes sont influencées par la taille des shards, la complexité des requêtes, la mise en cache et l'efficacité de la structure de données sous-jacente.
Causes et solutions :
Shards volumineux : Des shards trop volumineux peuvent ralentir les requêtes car Elasticsearch doit rechercher dans plus de données et fusionner les résultats de plus de segments.
- Diagnostic : Vérifiez les tailles des shards à l'aide de
_cat/shardsou_all/settings?pretty. - Solution : Visez des tailles de shards comprises entre 10 Go et 50 Go. Envisagez de réindexer les données dans un nouvel index avec des shards plus petits ou d'utiliser Index Lifecycle Management (ILM) pour gérer la taille des shards au fil du temps.
- Diagnostic : Vérifiez les tailles des shards à l'aide de
Trop de shards : Avoir un nombre excessif de petits shards peut entraîner une surcharge élevée pour le cluster, en particulier lors des recherches. Chaque shard nécessite des ressources pour la gestion.
- Diagnostic : Comptez le nombre total de shards par nœud et par index à l'aide de
_cat/shards. - Solution : Consolidez les index si possible. Optimisez votre modèle de données pour réduire le nombre d'index et donc le nombre total de shards. Pour les données de séries temporelles, ILM peut aider à gérer le nombre de shards.
- Diagnostic : Comptez le nombre total de shards par nœud et par index à l'aide de
Requêtes inefficaces : Les requêtes complexes, les requêtes impliquant des scripts lourds, les recherches par caractères génériques au début des termes ou les expressions régulières peuvent être très gourmandes en ressources.
- Diagnostic : Utilisez l'API Profile (
_search?profile=true) pour analyser le temps d'exécution des requêtes et identifier les parties lentes. Analysez les slow logs. - Solution : Simplifiez les requêtes. Évitez les caractères génériques en tête et les regex coûteuses. Utilisez les requêtes
termau lieu dematchpour les correspondances exactes lorsque cela est possible. Envisagez d'utiliser les suggesteurssearch_as_you_typeoucompletionpour les suggestions de saisie semi-automatique. Optimisez les clauses de filtre (utilisez le contextefilterau lieu du contextequerypour les requêtes sans notation).
- Diagnostic : Utilisez l'API Profile (
Manque de mise en cache : Une mise en cache insuffisante ou inefficace peut entraîner des calculs et des récupérations de données répétés.
- Diagnostic : Surveillez les taux de succès du cache pour le cache de requêtes et le cache de requêtes à l'aide de
_nodes/stats/indices/query_cacheet_nodes/stats/indices/request_cache. - Solution : Assurez-vous qu'une mise en cache appropriée est activée. Le cache de filtres (partie du cache de requêtes) est particulièrement important pour les requêtes de filtre répétées. Pour les requêtes identiques fréquemment exécutées, envisagez d'activer le cache de requêtes.
- Diagnostic : Surveillez les taux de succès du cache pour le cache de requêtes et le cache de requêtes à l'aide de
Surcharge de fusion de segments : Elasticsearch fusionne les petits segments en plus grands en arrière-plan. Ce processus consomme des ressources d'E/S et de CPU, ce qui peut parfois avoir un impact sur les performances des requêtes en temps réel.
- Diagnostic : Surveillez le nombre de segments par shard à l'aide de
_cat/segments. - Solution : Évitez de modifier les paramètres de fusion à la légère. Lors d'un important backfill, réduisez la fréquence d'actualisation, contrôlez la concurrence en masse et surveillez la limitation de la fusion et les E/S disque. Les force merges sont généralement destinés aux index en lecture seule, pas aux index chauds actifs.
- Diagnostic : Surveillez le nombre de segments par shard à l'aide de
3. Contention de ressources (CPU, Mémoire, Réseau)
La contention de ressources est une catégorie large qui peut se manifester à la fois par une dégradation des performances d'indexation et de requêtes.
Causes et solutions :
Surcharge CPU : Une utilisation élevée du CPU peut être causée par des requêtes complexes, des agrégations intensives, trop d'opérations d'indexation ou un garbage collection excessif.
- Diagnostic : Surveillez l'utilisation du CPU par nœud (
_nodes/stats). Identifiez les opérations qui consomment le plus de CPU (par exemple, recherche, indexation, GC JVM). - Solution : Optimisez les requêtes et les agrégations. Distribuez la charge sur plus de nœuds. Réduisez le taux d'indexation s'il submerge le CPU. Assurez des paramètres de tas JVM adéquats pour minimiser la surcharge du GC.
- Diagnostic : Surveillez l'utilisation du CPU par nœud (
Problèmes de mémoire (tas JVM et mémoire système) : Un tas JVM insuffisant entraîne des GC fréquents. L'épuisement de la mémoire système peut provoquer du swapping, réduisant considérablement les performances.
- Diagnostic : Surveillez l'utilisation du tas JVM et la mémoire système globale (RAM, swap) sur chaque nœud.
- Solution : Allouez suffisamment de tas JVM (par exemple, 50 % de la RAM système, jusqu'à 30,5 Go). Évitez le swapping en vous assurant qu'il y a suffisamment de mémoire système libre. Envisagez d'ajouter plus de nœuds ou d'utiliser des nœuds dédiés pour des rôles spécifiques (master, data, ingest).
Goulots d'étranglement réseau : Un trafic réseau élevé peut ralentir la communication inter-nœuds, la réplication et les requêtes des clients.
- Diagnostic : Surveillez l'utilisation de la bande passante réseau et la latence entre les nœuds et les clients.
- Solution : Optimisez l'infrastructure réseau. Réduisez les transferts de données inutiles. Assurez des paramètres d'allocation de shards et de réplication optimaux.
Saturation des E/S disque : Comme mentionné dans l'indexation, cela a également un impact sur les performances des requêtes lors de la lecture des données depuis le disque.
- Diagnostic : Surveillez les métriques d'E/S disque.
- Solution : Passez à un stockage plus rapide, distribuez les données sur plus de nœuds ou optimisez les requêtes pour réduire la quantité de données lues.
Meilleures pratiques pour l'optimisation des performances
- Surveillez en continu : L'optimisation des performances est un processus continu. Surveillez régulièrement la santé de votre cluster et l'utilisation des ressources.
- Optimisez les mappings : Définissez des mappings explicites et efficaces adaptés à vos données. Évitez les champs ou l'indexation inutiles.
- Stratégie de sharding : Visez des tailles de shards optimales (10-50 Go) et évitez d'avoir trop ou trop peu de shards.
- Utilisez l'API Bulk : Utilisez l'API Bulk pour l'indexation et l'API multi-search lorsque vous devez regrouper des recherches indépendantes.
- Réglez le tas JVM : Allouez suffisamment de tas, mais ne sur-allouez pas. Évitez le swapping.
- Comprenez les performances des requêtes : Profilez les requêtes, simplifiez-les et tirez parti du contexte de filtre.
- Tirez parti de la mise en cache : Assurez-vous que les caches de requêtes et de requêtes sont utilisés efficacement.
- Matériel : Utilisez des SSD pour le stockage et assurez-vous d'avoir un CPU et une RAM adéquats.
- Nœuds dédiés : Envisagez d'utiliser des nœuds dédiés pour les rôles master, data et ingest afin d'isoler les charges de travail.
- Index Lifecycle Management (ILM) : Pour les données de séries temporelles, ILM est essentiel pour gérer les index, faire rouler les shards et finalement supprimer les anciennes données, ce qui aide à contrôler le nombre et la taille des shards.
Lorsque vous trouvez un goulot d'étranglement, apportez le plus petit changement qui y remédie directement. Ajoutez des nœuds lorsque le cluster est vraiment à court de capacité. Corrigez les mappings lorsque le tas est gaspillé. Réécrivez les requêtes lorsque la sortie du profil pointe vers des clauses coûteuses. Ajustez la stratégie de sharding lorsqu'un nœud effectue un travail qui devrait être réparti. Cette discipline empêche le travail de performance de devenir un tas de boutons de réglage sans rapport.