Gestion de la mémoire Elasticsearch et résolution des problèmes

Avec Elastic Cloud, qui propose des solutions telles que Observability, Security et Search, nous avons élargi le nombre d’utilisateurs d’Elastic Cloud au-delà des équipes opérationnelles complètes pour inclure les ingénieurs de données, les équipes de sécurité et les consultants. En tant que représentant du support Elastic, j’ai eu le plaisir d’interagir avec un large éventail d’utilisateurs et de cas d’utilisation.

Avec un public plus large, je reçois de plus en plus de questions concernant la gestion de l’allocation des ressources, en particulier le dépannage de l’état de l’allocation et l’évitement du déclenchement des disjoncteurs. C’est tout à fait compréhensible ! Quand j’ai commencé à utiliser Elasticsearch, je me posais les mêmes questions. C’était ma première expérience dans la gestion de segments Java et de partitions de bases de données temporelles, et dans le scaling de ma propre infrastructure.

Lorsque j’ai rejoint Elastic, j’ai particulièrement apprécié le fait de disposer, en plus de la documentation, d’articles et de tutoriels pour pouvoir être opérationnel rapidement. Mais le premier mois, cela a été difficile d’appliquer mes connaissances théoriques aux erreurs soumises par les utilisateurs via des tickets. Tout comme d’autres membres de l’assistance technique, je suis finalement parvenu à la conclusion qu’un grand nombre des erreurs signalées étaient simplement symptomatiques de problèmes d’allocation et que la même demi-douzaine de liens permettrait aux utilisateurs d’apprendre à gérer correctement leur allocation de ressources.

En tant que représentant de l’assistance technique, je vais aborder les principaux liens théoriques sur la gestion de l’allocation que nous envoyons aux utilisateurs, les symptômes les plus courants que nous observons, et les endroits vers lesquels nous redirigeons les utilisateurs pour mettre à jour leurs configurations afin de résoudre leurs problèmes d’allocation de ressources.

Théorie

En tant qu’application Java, Elasticsearch nécessite une allocation de mémoire logique (heap) depuis la mémoire physique du système. Cela devrait représenter jusqu’à la moitié de la RAM physique, avec un plafondà 32 Go. Augmenter l’utilisation du tas est généralement une réponse à des requêtes coûteuses et à une capacité de stockage de données plus importante. Le disjoncteur parent est réglé par défaut à 95 %, mais nous vous recommandons un scaling des ressources une fois que vous atteignez régulièrement 85 %. 

Je recommande vivement ces articles de synthèse pour plus d’informations :

Configuration

Par défaut, Elasticsearch dimensionne automatiquement la mémoire JVM en fonction du rôle du Node et de la mémoire totale. Cependant, vous pouvez la configurer directement selon vos besoins, de trois manières différentes :

1. Directement dans votre fichier de configuration > jvm.options de vos fichiers Elasticsearch locaux :

## JVM configuration

################################################################
## IMPORTANT: JVM heap size
################################################################

…

# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space

-Xms4g
-Xmx4g

2. En tant que variable d’environnement Elasticsearch dans votre fichier docker-compose :

version: '2.2'
services:
  es01:
	image: docker.elastic.co/elasticsearch/elasticsearch:7.12.0
	environment:
  	- node.name=es01
  	- cluster.name=es
  	- bootstrap.memory_lock=true
  	- "ES_JAVA_OPTS=-Xms4g -Xmx4g"
  	- discovery.type=single-node
	ulimits:
  	memlock:
    	soft: -1
    	hard: -1
	ports:
  	- 9200:9200

3. Via notre Elastic Cloud Hosted > Déploiement > Modifier la vue. Remarque : le menu déroulant attribue la mémoire physique, dont environ la moitié sera allouée au heap.

Niveau Données et contenu à forte activité d'Elasticsearch

Résolution des problèmes

Si vous rencontrez actuellement des problèmes de performances sur votre cluster, ceux-ci s’expliquent probablement par les raisons habituelles :

  • Problèmes de configuration : nœuds maîtres sous-dimensionnés, pas de politique ILM
  • Induit par le volume : cadence élevée de requêtes/charge, chevauchement de requêtes/écritures coûteuses
Toutes les requêtes cURL/API suivantes peuvent être effectuées dans Elastic Cloud Hosted > Console API Elasticsearch, sous forme de cURL vers l’API Elasticsearch, ou sous Kibana > Outils de développement.

Allocation santé

Les index de données sont stockés dans des sous-partitions, qui utilisent le heap pour la maintenance et lors des requêtes de recherche/écriture. La taille d'une partition ne doit pas dépasser 50 Go. Prenons l’exemple de l’hébergement Elastic Cloud Hosted mentionné ci-dessus avec 8 Go de mémoire physique répartis sur deux zones (ce qui allouera deux nœuds au total) et appliquons-le à l’exemple suivant : _cat/allocation.

GET /_cat/allocation?v=true&h=shards,node
shards node
    41 instance-0000000001
    41 instance-0000000000

Et à : _cluster/health.

GET /_cluster/health?filter_path=status,*_shards

{
  "status": "green",
  "unassigned_shards": 0,
  "initializing_shards": 0,
  "active_primary_shards": 41,
  "relocating_shards": 0,
  "active_shards": 82,
  "delayed_unassigned_shards": 0
}

Si des partitions signalent une valeur > 0 en dehors de active_shards ou de active_primary_shards, vous avez identifié une cause de problèmes de performances.

Le plus souvent, si ce rapport indique un problème, le nombre de partitions non attribuées sera supérieur à 0. Si ces partitions sont primaires, votre cluster affichera un statut rouge (status:red), et s’il ne s’agit que de réplicas, le statut sera jaune (status:yellow). (C’est pourquoi il est important de configurer des réplicas sur les index : en cas de problème, le cluster peut récupérer et éviter ainsi toute perte de données.) Imaginons un cluster avec un statut jaune (status:yellow) et une seule partition non attribuée. Pour analyser le problème, nous examinerons quelle partition d’index pose problème via la commande « _cat/shards ».

GET _cat/shards?v=true&s=state
index                                 	shard prirep state    	docs   store ip       	node
logs                                  	0 	p  	STARTED     	2  10.1kb 10.42.255.40 instance-0000000001
logs                                  	0 	r  	UNASSIGNED
kibana_sample_data_logs               	0 	p  	STARTED 	14074  10.6mb 10.42.255.40 instance-0000000001
.kibana_1                             	0 	p  	STARTED  	2261   3.8mb 10.42.255.40 instance-0000000001

Cela concerne donc nos logs d’index non système, qui possèdent une partition de réplique non attribuée. Voyons ce qui pose problème en exécutant _cluster/allocation/explain. (Info : lorsque vous contactez l’assistance, c’est exactement ce que nous faisons.)

GET _cluster/allocation/explain?pretty&filter_path=index,node_allocation_decisions.node_name,node_allocation_decisions.deciders.*

{ "index": "logs",
  "node_allocation_decisions": [{
      "node_name": "instance-0000000005",
      "deciders": [{
          "decider": "data_tier",
          "decision": "NO",
          "explanation": "node does not match any index setting [index.routing.allocation.include._tier] tier filters [data_hot]"
}]}]}

Ce message d’erreur pointe vers data_hot, qui fait partie d’une gestion du cycle de vie des index (ILM) et indique que notre politique ILM n’est pas compatible avec nos paramètres actuels d’index. Dans ce cas, la cause de cette erreur vient de la configuration d’une politique ILM hot-warm sans nœuds hot-warm désignés. (J’ai dû m’assurer qu’une erreur se produirait, donc je vous propose des exemples d’erreurs. Pour plus d’informations, consultez cette vidéo d’exemple de dépannage pour le déroulement de la résolution.)

Si vous exécutez cette commande alors que vous n’avez aucune partition non attribuée, vous obtiendrez une erreur 400 indiquant l’impossibilité de trouver des partitions non attribuées à expliquer car aucun problème n’est détecté.Si la cause de l’erreur est non logique (par exemple, une erreur réseau temporaire comme Node left cluster during allocation), vous pouvez utiliser la fonction pratique _cluster/reroute d’Elastic.

POST /_cluster/reroute

Cette requête sans personnalisation lance un processus asynchrone en arrière-plan qui tente d’allouer toutes les partitions en état non attribué (state:UNASSIGNED). (Ne faites pas comme moi : n’attendez pas que cela se termine avant de contacter les développeurs, car je pensais que ce serait instantané et que cela escaladerait juste à temps pour qu’ils disent qu’il n’y avait plus de problème.) Pour plus d’informations, consultez cette vidéo de dépannage pour surveiller la qualité de l’allocation.

Disjoncteurs

La saturation de l’allocation de segment peut entraîner l’expiration ou l’échec des requêtes envoyées au cluster et provoquera souvent des exceptions de disjoncteur au sein de ce dernier. Les erreurs de disjoncteur entraînent des événements dans elasticsearch.log tels que :

Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [<transport_request>] would be [num/numGB], which is larger than the limit of [num/numGB], usages [request=0/0b, fielddata=num/numKB, in_flight_requests=num/numGB, accounting=num/numGB]

Pour comprendre ce qui se passe, vérifiez heap.percent, soit en passant par _cat/nodes :

GET /_cat/nodes?v=true&h=name,node*,heap*
# heap = JVM (logical memory reserved for heap)
# ram  = physical memory

name                                node.role heap.current heap.percent heap.max
tiebreaker-0000000002 mv             119.8mb           23    508mb
instance-0000000001   himrst           1.8gb           48    3.9gb
instance-0000000000   himrst           2.8gb           73    3.9gb

Ou, si vous l’avez déjà activé, accédez à Kibana > Stack Monitoring.

Nœuds Elasticsearch

S’il est avéré que vous avez atteint le seuil de déclenchement des disjoncteurs de mémoire, envisagez d’augmenter le segment de manière temporaire afin que vous puissiez souffler et prendre le temps de faire des recherches sur l’origine du problème. Lorsque vous recherchez la cause première d’un problème, parcourez le journal d’audit, le journal des requêtes lentes, les clusterlogs ou le fichier elasticsearch.log pour voir les événements consécutifs qui précèdent. Recherchez :

  • les requêtes gourmandes en ressources, plus particulièrement :
    • de nombreuses agrégations de buckets ;
      • Je me suis senti si bête lorsque j’ai découvert que les recherches allouaient temporairement une certaine portion du segment avant d’exécuter la requête selon la taille des recherches ou des dimensions d’un bucket, si bien qu’un paramétrage de 10 000 000 a vraiment donné des sueurs froides à mon équipe opérationnelle.
    • les mappings non optimisés ;
      • la seconde raison pour laquelle je me suis senti bête, c’est quand je pensais qu’un reporting hiérarchique donnerait de meilleurs résultats de recherche que des données lissées (ce n’est pas le cas).
  • Volume/rythme des demandes : généralement des requêtes par lots ou asynchrones

Quand l’heure de scaler arrive...

Si ce n’est pas la première fois que vous atteignez le seuil de déclenchement des disjoncteurs ou que vous suspectez qu’un problème s’est installé de façon permanente (par exemple si vous atteignez systématiquement le seuil de 85 %, ce qui signifie qu’il est temps d’envisager de scaler les ressources), nous vous recommandons de garder un œil sur la pression de mémoire JVM, qui sert d’indicateur à long terme pour votre segment. Vous pouvez vérifier ce point dans Elastic Cloud Hosted > Déploiement.

Instances Elasticsearch

Ou vous pouvez le calculer à partir de _nodes/statistiques :

GET /_nodes/stats?filter_path=nodes.*.jvm.mem.pools.old

{"nodes": { "node_id": { "jvm": { "mem": { "pools": { "old": {
  "max_in_bytes": 532676608,
  "peak_max_in_bytes": 532676608,
  "peak_used_in_bytes": 104465408,
  "used_in_bytes": 104465408
}}}}}}}

Où :

JVM Memory Pressure = used_in_bytes / max_in_bytes

Des symptômes potentiels sont la fréquence élevée et la durée prolongée des événements du récupérateur de mémoire (gc) dans elasticsearch.log :

[timestamp_short_interval_from_last][INFO ][o.e.m.j.JvmGcMonitorService] [node_id] [gc][number] overhead, spent [21s] collecting in the last [40s]

Si ces deux symptômes sont présents, vous devriez envisager soit de scaler votre cluster, soit de réduire le nombre de demandes à traiter. Voici ce que vous pouvez faire pour résoudre le problème :

  • Augmentation des ressources du segment (heap/nœud ; nombre de nœuds)
  • Réduction des partitions (supprimer les données inutiles/anciennes ; utiliser l’ILM pour placer les données dans un stockage chaud/froid afin de pouvoir les compacter ; désactiver les répliques pour les données dont la perte n’est pas critique)

Nous sommes là pour vous aider

Ouah ! D’après ce que je vois dans l‘assistance technique Elastic, voici une synthèse des tickets d’utilisateurs les plus courants : partitions non attribuées, mauvais équilibre partition/segment, disjoncteurs, récupération de mémoire élevée et erreurs d’allocation. Tous ces symptômes sont liés à la gestion de l’allocation des ressources. Heureusement, vous connaissez à présent la théorie et la résolution associée.

Néanmoins, si vous ne parvenez pas à résoudre un problème, n’hésitez pas à nous écrire. Nous serons très heureux de vous aider ! Contactez-nous : 

Vive notre capacité à gérer l’allocation des ressources de la Suite Elastic en tant que non-Ops (nous aimons aussi les Ops !) !

Initialement publié le 27 avril 2021 ; mis à jour le 5 novembre 2024.

La publication et la date de publication de toute fonctionnalité ou fonction décrite dans le présent article restent à la seule discrétion d'Elastic. Toute fonctionnalité ou fonction qui n'est actuellement pas disponible peut ne pas être livrée à temps ou ne pas être livrée du tout.