Dépannage des requêtes Elasticsearch lentes : identification et étapes de résolution
Comment diagnostiquer les requêtes Elasticsearch lentes à l'aide de contrôles de santé, de journaux de lenteur, de l'API Profile, des mappings, des shards et de modèles de requêtes plus sûrs.
Dépannage des requêtes Elasticsearch lentes : identification et étapes de résolution
Les requêtes Elasticsearch lentes sont rarement résolues par un seul paramètre universel. Une requête peut être lente car elle analyse trop de données, touche trop de shards, demande une agrégation coûteuse, trie sur le mauvais champ, attend derrière d'autres travaux, ou atterrit sur un nœud déjà à court de mémoire de tas ou de bande passante disque.
Commencez par la requête réelle si vous pouvez l'obtenir. Un rapport vague indiquant que "la recherche est lente" est difficile à traiter. Un corps de requête copié, un modèle d'index cible, une plage de temps, une latence côté utilisateur et un horodatage vous permettent de comparer la requête lente avec les métriques du cluster du même moment.
Comprendre la latence des requêtes Elasticsearch
Avant de plonger dans le dépannage, il est essentiel de comprendre les principaux facteurs qui influencent les performances des requêtes dans Elasticsearch :
- Volume et complexité des données : La quantité de données, le nombre de champs et la complexité des documents peuvent avoir un impact direct sur les temps de recherche.
- Complexité de la requête : Les requêtes
termsimples sont rapides ; les requêtesboolcomplexes avec de nombreuses clauses, agrégations ou requêtesscriptpeuvent être gourmandes en ressources. - Stratégie de mapping et d'indexation : La façon dont vos données sont indexées (par exemple, champs
textvskeyword, utilisation defielddata) affecte considérablement l'efficacité des requêtes. - Santé et ressources du cluster : Le CPU, la mémoire, les E/S disque et la latence réseau sur vos nœuds de cluster sont essentiels. Un cluster en mauvaise santé ou des nœuds à ressources limitées entraîneront inévitablement des performances lentes.
- Sharding et réplication : Le nombre et la taille des shards, ainsi que leur répartition sur les nœuds, ont un impact sur le parallélisme et la récupération des données.
Vérifications initiales pour les requêtes lentes
Avant d'utiliser des outils de profilage avancés, commencez toujours par ces vérifications fondamentales :
1. Surveiller la santé du cluster
Vérifiez l'état général de votre cluster Elasticsearch à l'aide de l'API _cluster/health. Un statut red indique des shards primaires manquants, et yellow signifie que certains shards de réplica ne sont pas alloués. Les deux peuvent gravement affecter les performances des requêtes.
GET /_cluster/health
Recherchez status: green, mais ne vous arrêtez pas là. Un cluster vert peut toujours être surchargé, mal shardé ou exécuter des requêtes inefficaces.
2. Vérifier les ressources des nœuds
Examinez l'utilisation des ressources des nœuds individuels. Une utilisation élevée du CPU, une faible mémoire disponible (en particulier le tas) ou des E/S disque saturées sont des indicateurs forts de goulots d'étranglement.
GET /_cat/nodes?v
GET /_cat/thread_pool?v
Faites attention à cpu, load_1m, heap.percent et disk.used_percent. Des tailles de file d'attente élevées du pool de threads search indiquent également une surcharge.
3. Analyser les journaux de lenteur
Elasticsearch peut enregistrer les requêtes qui dépassent un seuil défini. C'est une excellente première étape pour identifier des requêtes lentes spécifiques sans plonger en profondeur dans chaque demande individuelle.
Les seuils des journaux de lenteur sont des paramètres d'index. Appliquez-les à l'index ou au modèle d'index concerné afin de capturer des exemples utiles sans inonder chaque journal de nœud :
PUT /my-index/_settings
{
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.fetch.warn": "1s"
}
Ensuite, surveillez vos journaux Elasticsearch pour des entrées comme [WARN][index.search.slowlog].
Analyse approfondie : identification des goulots d'étranglement avec l'API Profile
Lorsque les vérifications initiales ne permettent pas d'identifier le problème, ou que vous devez comprendre pourquoi une requête spécifique est lente, l'API Profile d'Elasticsearch est votre outil le plus puissant. Elle fournit une ventilation détaillée de la façon dont une requête s'exécute à un niveau bas, y compris le temps passé par chaque composant.
Qu'est-ce que l'API Profile ?
L'API Profile renvoie un plan d'exécution complet pour une demande de recherche, détaillant le temps pris pour chaque composant de la requête (par exemple, TermQuery, BooleanQuery, WildcardQuery) et la phase de collecte. Cela vous permet d'identifier exactement quelles parties de votre requête consomment le plus de temps.
Comment utiliser l'API Profile
Ajoutez simplement "profile": true au corps de votre demande de recherche existante :
GET /your_index/_search?profile=true
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" } }
],
"filter": [
{ "range": { "date": { "gte": "now-1y/y" } } }
]
}
},
"size": 0,
"aggs": {
"daily_sales": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1d"
}
}
}
}
Remarque : L'API Profile ajoute une surcharge, utilisez-la donc pour déboguer des requêtes spécifiques, pas en production pour chaque demande.
Interprétation de la sortie de l'API Profile
La sortie est verbeuse mais structurée. Les champs clés à rechercher dans la section profile incluent :
type: Le type de requête Lucene ou de collecteur en cours d'exécution (par exemple,BooleanQuery,TermQuery,WildcardQuery,MinScoreCollector).description: Une description lisible par l'homme du composant, incluant souvent le champ et la valeur sur lesquels il opère.time_in_nanos: Le temps total (en nanosecondes) passé par ce composant et ses enfants.breakdown: Une ventilation détaillée du temps passé dans différentes phases (par exemple,rewrite,build_scorer,next_doc,advance,score).
Exemple d'interprétation : Si vous voyez une WildcardQuery ou RegexpQuery avec un time_in_nanos élevé et une partie significative passée dans rewrite, cela indique que la réécriture de la requête (expansion du motif générique) est très coûteuse, en particulier sur les champs à haute cardinalité ou les grands index.
...
"profile": {
"shards": [
{
"id": "_na_",
"searches": [
{
"query": [
{
"type": "BooleanQuery",
"description": "title:elasticsearch +date:[1577836800000 TO 1609459200000}",
"time_in_nanos": 12345678,
"breakdown": { ... },
"children": [
{
"type": "TermQuery",
"description": "title:elasticsearch",
"time_in_nanos": 123456,
"breakdown": { ... }
},
{
"type": "PointRangeQuery",
"description": "date:[1577836800000 TO 1609459200000}",
"time_in_nanos": 789012,
"breakdown": { ... }
}
]
}
],
"aggregations": [
{
"type": "DateHistogramAggregator",
"description": "date_histogram(field=timestamp,interval=1d)",
"time_in_nanos": 9876543,
"breakdown": { ... }
}
]
}
]
}
]
}
...
Dans cet exemple simplifié, si DateHistogramAggregator montre un time_in_nanos disproportionné, votre agrégation est le goulot d'étranglement.
Causes courantes des requêtes lentes et stratégies de résolution
En fonction de vos conclusions de l'API Profile et de l'état général du cluster, voici les problèmes courants et leurs solutions :
1. Conception de requête inefficace
Problème : Certains types de requêtes sont intrinsèquement gourmands en ressources, en particulier sur de grands ensembles de données.
- Requêtes
wildcard,prefix,regexp: Elles peuvent être très lentes car elles doivent parcourir de nombreux termes. - Requêtes
script: Exécuter des scripts sur chaque document pour le filtrage ou le scoring est extrêmement coûteux. - Pagination profonde : Utiliser
frometsizeavec de très grands décalages. - Trop de clauses
should: Les requêtes booléennes avec des centaines ou des milliers de clausesshouldpeuvent devenir très lentes.
Étapes de résolution :
- Évitez les requêtes
wildcard/prefix/regexplarges sur les grands champs :- Pour la recherche au fur et à mesure de la frappe, utilisez des
completion suggestersou desn-gramsau moment de l'indexation. - Pour les préfixes exacts, envisagez des champs de préfixe dédiés,
index_prefixes, ou une stratégiekeywordqui correspond à vos données.
- Pour la recherche au fur et à mesure de la frappe, utilisez des
- Minimisez les requêtes
script: Réévaluez si la logique peut être déplacée vers l'ingestion (par exemple, en ajoutant un champ dédié) ou gérée par des requêtes/agrégations standard. - Optimisez la pagination : Pour la pagination profonde côté utilisateur, utilisez
search_afteravec un tri stable. Utilisez l'API scroll pour les travaux d'extraction par lots, pas pour les pages de recherche interactives. - Refactorisez les requêtes
should: Combinez des clauses similaires, ou envisagez un filtrage côté client si approprié.
2. Mappings manquants ou inefficaces
Problème : Des mappings de champ incorrects peuvent forcer Elasticsearch à effectuer des opérations coûteuses.
- Champs texte utilisés pour la correspondance exacte/le tri/les agrégations : Les champs
textsont analysés et tokenisés, rendant la correspondance exacte inefficace. Le tri ou l'agrégation sur ceux-ci nécessitefielddata, ce qui est gourmand en mémoire de tas. - Sur-indexation : Indexer des champs qui ne sont jamais recherchés ou analysés inutilement.
Étapes de résolution :
- Utilisez
keywordpour les correspondances exactes, le tri et les agrégations : Pour les champs nécessitant une correspondance exacte, un filtrage, un tri ou des agrégations, utilisez le type de champkeyword. - Utilisez les
multi-fields: Indexez les mêmes données de différentes manières (par exemple,title.textpour la recherche en texte intégral ettitle.keywordpour la correspondance exacte et les agrégations). - Désactivez
indexpour les champs inutilisés : Si un champ est uniquement affiché et jamais recherché, envisagez"index": false. Soyez prudent avec la désactivation de_source; cela affecte les mises à jour, la réindexation, le débogage et les workflows de récupération.
3. Problèmes de sharding
Problème : Un nombre ou une taille de shards inapproprié peut entraîner une répartition inégale de la charge ou une surcharge excessive.
- Trop de petits shards : Chaque shard a une surcharge. Trop de petits shards peuvent stresser le nœud maître, augmenter l'utilisation du tas et ralentir les recherches en augmentant le nombre de requêtes.
- Trop peu de grands shards : Limite le parallélisme lors des recherches et peut créer des "points chauds" sur les nœuds.
Étapes de résolution :
- Dimensionnement optimal des shards : Visez des tailles de shard entre 10 Go et 50 Go. Utilisez des index basés sur le temps (par exemple,
logs-YYYY.MM.DD) et des index rollover pour gérer la croissance des shards. - Réindexez et réduisez/divisez : Utilisez les API
_reindex,_splitou_shrinkpour consolider ou redimensionner les shards sur les index existants. - Surveillez la distribution des shards : Assurez-vous que les shards sont répartis uniformément sur les nœuds de données.
4. Paramètres de tas et JVM
Problème : Une mémoire de tas JVM insuffisante ou un garbage collection sous-optimal peuvent provoquer des pauses fréquentes et de mauvaises performances.
Étapes de résolution :
- Allouez suffisamment de tas : Définissez
XmsetXmxà la même valeur. Un point de départ courant est de ne pas dépasser la moitié de la RAM physique tout en restant en dessous du seuil de pointeur d'objet compressé ordinaire, souvent autour de la plage des 30 Go. - Surveillez le garbage collection JVM : Utilisez
GET _nodes/stats/jvm?prettyou des outils de surveillance dédiés pour vérifier les temps de GC. Des GC fréquents ou longs indiquent une pression sur le tas.
5. E/S disque et latence réseau
Problème : Un stockage lent ou des goulots d'étranglement réseau peuvent être une cause fondamentale de la latence des requêtes.
Étapes de résolution :
- Utilisez un stockage rapide : Les SSD sont fortement recommandés pour les nœuds de données Elasticsearch. Les SSD NVMe sont encore meilleurs pour les cas d'utilisation à hautes performances.
- Assurez une bande passante réseau adéquate : Pour les grands clusters ou les environnements fortement indexés/interrogés, le débit réseau est critique.
6. Utilisation de Fielddata
Problème : L'utilisation de fielddata sur les champs text pour le tri ou les agrégations peut consommer des quantités massives de mémoire de tas et entraîner des exceptions OutOfMemoryError.
Étapes de résolution :
- Évitez
fielddata: truesur les champstext: Ce paramètre est désactivé par défaut pour les champstextpour une bonne raison. Utilisez plutôt lesmulti-fieldspour créer un sous-champkeywordpour le tri/les agrégations.
Meilleures pratiques pour l'optimisation des requêtes
Pour prévenir proactivement les requêtes lentes :
- Préférez le contexte
filterpour les conditions sans scoring : Si vous n'avez pas besoin de scoring de pertinence pour les conditionsrange,termouexists, placez-les dans la clausefilterd'une requêtebool. Les filtres ignorent le scoring et sont souvent plus faciles à optimiser pour Elasticsearch. - Utilisez la requête
constant_scorepour le filtrage : Cela est utile lorsque vous avez unequery(pas unfilter) que vous souhaitez exécuter dans un contexte de filtre pour les avantages de la mise en cache. - Concevez pour la réutilisation du cache là où cela convient : Elasticsearch décide automatiquement quoi mettre en cache. Les filtres répétés sur des données stables bénéficient plus que les filtres uniques et ponctuels avec des valeurs en constante évolution.
- Ajustez
indices.query.bool.max_clause_count: Si vous atteignez la limite par défaut (1024) avec de nombreuses clausesshould, envisagez de reconcevoir votre requête ou d'augmenter ce paramètre (avec prudence). - Surveillance régulière : Surveillez en continu la santé de votre cluster, les ressources des nœuds, les journaux de lenteur et les performances des requêtes pour détecter les problèmes tôt.
- Testez, testez, testez : Testez toujours les performances des requêtes avec des volumes de données et des charges de travail réalistes dans un environnement de préproduction avant de déployer en production.
La meilleure correction de requête est généralement visible dans les preuves. Les journaux de lenteur montrent la forme de la requête. L'API Profile montre quelle partie de la requête consomme du temps. Les statistiques des nœuds montrent si le cluster avait suffisamment de CPU, de tas et d'E/S disque lorsque la requête a été exécutée. Rassemblez ces éléments avant de modifier les paramètres, et vous éviterez de régler un symptôme pendant que le vrai problème continue de s'exécuter.