«Une personne formée marche également sur un râteau.
Mais d'un autre côté, où se trouve le stylo. »Elasticsearch est un excellent outil, mais chaque outil nécessite non seulement un
réglage et une
maintenance , mais également une attention aux détails. Certains sont insignifiants et reposent à la surface, tandis que d'autres sont cachés si profondément qu'il faudra plus d'une journée pour fouiller, pas une douzaine de tasses de café et pas un kilomètre de nerfs. Dans cet article, je vais vous parler de neuf merveilleux râteaux dans les réglages élastiques sur lesquels j'ai marché.
Je vais organiser le râteau par ordre décroissant de preuve. De ceux qui peuvent être prévus et contournés au stade de la création et de l'entrée d'un cluster à l'état de production, à ceux très étranges qui apportent le plus d'expérience (et d'étoiles dans les yeux).
Les nœuds de données doivent être identiques
«Le cluster fonctionne à la vitesse du nœud de données le plus lent» - un axiome agonisé. Mais il y a un autre point évident qui n'est pas lié aux performances: l'élastique ne pense pas dans l'espace disque, mais dans les fragments, et essaie de les répartir uniformément entre les nœuds de données. Si certains des nœuds de données ont plus d'espace que d'autres, il sera inutile de rester inactif.
Deprecation.log
Il peut arriver que quelqu'un n'utilise pas les moyens les plus modernes pour envoyer des données à l'élastique, qui ne peut pas définir le type de contenu lors de l'exécution des requêtes. Dans cette liste, par exemple, heka, ou lorsque les journaux quittent les appareils par leurs moyens intégrés). Dans ce cas, dépréciation. journal commence à croître à un rythme alarmant, et pour chaque demande, les lignes suivantes y apparaissent:
[2018-07-07T14:10:26,659][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,670][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,671][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,673][WARN ][oedrRestController] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header. [2018-07-07T14:10:26,677][WARN ][oedrRestController ] Content type detection for rest requests is deprecated. Specify the content type using the [Content-Type] header.
Les demandes arrivent, en moyenne, toutes les 5 à 10 ms - et chaque fois qu'une nouvelle ligne est ajoutée au journal. Cela affecte négativement les performances du sous-système de disque et augmente iowait. Deprecation.log peut être désactivé, mais ce n'est pas trop raisonnable. Pour y collecter des journaux élastiques, mais pas pour les détritus, je désactive uniquement les journaux de la classe oedrRestController.
Pour ce faire, ajoutez la construction suivante à logs4j2.properties:
logger.restcontroller.name = org.elasticsearch.deprecation.rest.RestController logger.restcontroller.level = error
Cela augmentera les journaux de cette classe au niveau d'erreur et ils ne tomberont plus dans deprecation.log.
.kibana
À quoi ressemble un processus d'installation de cluster typique? Nous mettons les nœuds, les combinons dans un cluster, mettons le x-pack (qui en a besoin), et bien sûr, Kibana. Nous commençons, vérifions que tout fonctionne et Kibana voit le cluster, et continuons de configurer. Le problème est que sur un cluster fraîchement installé, le modèle par défaut ressemble à ceci:
{ "default": { "order": 0, "template": "*", "settings": { "number_of_shards": "1", "number_of_replicas": "0" } }, "mappings": {}, "aliases": {} }
Et l'index .kibana, où tous les paramètres sont stockés, est créé en une seule copie.
Il y a eu un cas où, en raison d'une défaillance matérielle, l'un des nœuds de données du cluster a été tué. Il a rapidement atteint un état cohérent, générant des répliques du fragment à partir des nœuds de données voisins, mais, heureusement, c'est sur ce nœud de données que le seul fragment avec l'index .kibana a été localisé. La situation est dans l'impasse - le cluster est vivant, en état de marche et Kibana est en statut rouge, et mon téléphone est déchiré par les appels des employés qui ont un besoin urgent de leurs journaux.
Tout cela est résolu simplement. Jusqu'à présent, rien n'est tombé:
XPUT .kibana/_settings { "index": { "number_of_replicas": "<__>" } }
XMX / XMS
La
documentation dit «pas plus de 32 Go», et à juste titre. Mais il est également correct que vous n'ayez pas besoin d'installer dans les paramètres de service
-Xms32g -Xmx32g
Parce que c'est déjà plus de 32 gigaoctets, et ici nous rencontrons une nuance intéressante de Java travaillant avec la mémoire. Au-delà d'une certaine limite, Java cesse d'utiliser des pointeurs compressés et commence à consommer beaucoup trop de mémoire. Vérifier si les pointeurs compressés utilisent une machine Java exécutant Elasticsearch est très simple. Nous regardons dans le journal de service:
[2018-07-29T15:04:22,041][INFO][oeeNodeEnvironment][log-elastic-hot3] heap size [31.6gb], compressed ordinary object pointers [true]
La quantité de mémoire à ne pas dépasser dépend, entre autres, de la version de Java utilisée. Pour calculer le volume exact dans votre cas, consultez la
documentation .
Maintenant, j'ai installé sur tous les nœuds de données de l'élastique:
-Xms32766m -Xmx32766m
Cela semble être un fait banal, et la documentation est bien décrite, mais je rencontre régulièrement des installations Elasticsearch où j'ai raté ce point, et Xms / Xmx sont définis sur 32g.
/ var / lib / elasticsearch
Il s'agit du chemin par défaut pour le stockage des données dans elasticsearch. yml:
path.data: /var/lib/elasticsearch
Là, je monte généralement une grande matrice RAID, et voici pourquoi: nous spécifions ES de plusieurs façons pour stocker des données, par exemple, comme ceci:
path.data: /var/lib/elasticsearch/data1, /var/lib/elasticsearch/data2
Différents disques ou tableaux RAID sont montés dans data1 et data2. Mais l'élastique ne s'équilibre pas et ne répartit pas la charge entre ces chemins. Tout d'abord, il remplit une section, puis commence à écrire dans une autre, de sorte que la charge sur le stockage sera inégale. Sachant cela, j'ai pris une décision sans ambiguïté - j'ai combiné tous les disques dans RAID0 / 1 et l'ai monté dans le chemin spécifié dans path.data.
processeurs_disponibles
Et non, je ne parle pas des processeurs sur les nœuds d'ingestion maintenant. Si vous regardez les propriétés d'un nœud en cours d'exécution (via l'API _nodes), vous pouvez voir quelque chose comme ceci:
"os". { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-87-generic", "available_processors": 28, "allocated_processors": 28 }
On peut voir que le nœud fonctionne sur un hôte avec 28 cœurs, et l'élastique a correctement déterminé leur nombre et a commencé sur tous. Mais s'il y a plus de 32 cœurs, cela arrive parfois comme ceci:
"os": { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-116-generic", "available_processors": 72, "allocated_processors": 32 }
Vous devez forcer le nombre de processeurs disponibles pour le service - cela a un bon effet sur les performances du nœud.
processors: 72
thread_pool.bulk.queue_size
Dans la section thread_pool.bulk.rejected du dernier
article, il y avait une telle mesure - le nombre du nombre d'échecs pour les demandes d'ajout de données.
J'ai écrit que la croissance de cet indicateur est un très mauvais signe, et les développeurs recommandent de ne pas configurer de pools de threads, mais d'ajouter de nouveaux nœuds au cluster - soi-disant, cela résout les problèmes de performances. Mais les règles sont nécessaires pour les briser parfois. Et il n'est pas toujours possible de "jeter le problème avec du fer", donc l'une des mesures pour lutter contre les échecs dans les demandes groupées est d'augmenter la taille de cette file d'attente.
Par défaut, les paramètres de file d'attente ressemblent à ceci:
"thread_pool": { "bulk": { "type": "fixed", "min": 28, "max": 28, "queue_size": 200 } }
L'algorithme est le suivant:
- Nous collectons des statistiques sur la taille moyenne de la file d'attente pendant la journée (la valeur instantanée est stockée dans thread_pool.bulk.queue);
- Augmentez soigneusement queue_size à des tailles légèrement supérieures à la taille moyenne de la file d'attente active - car une défaillance se produit lorsqu'elle est dépassée;
- Nous augmentons la taille de la piscine - ce n'est pas nécessaire, mais acceptable.
Pour ce faire, ajoutez quelque chose comme ça aux paramètres de l'hôte (vous aurez, bien sûr, vos propres valeurs):
thread_pool.bulk.size: 32 thread_pool.bulk.queue_size: 500
Et après avoir redémarré le nœud, nous surveillerons certainement la charge, les E / S et la consommation de mémoire. et tout ce qui est possible pour restaurer les paramètres si nécessaire.
Important: ces paramètres n'ont de sens que sur les nœuds travaillant sur la réception de nouvelles données.Création d'un index préliminaire
Comme je l'ai dit dans le premier
article de la série, nous utilisons Elasticsearch pour stocker les journaux de tous les microservices. L'essentiel est simple: un index stocke les journaux d'un composant en une journée.
Il en résulte que chaque jour de nouveaux index sont créés par le nombre de microservices - par conséquent, plus tôt chaque nuit, l'élastique est tombé dans le corps à corps pendant environ 8 minutes, tandis qu'une centaine de nouveaux index ont été créés, plusieurs centaines de nouveaux fragments, le programme de chargement du disque est sorti du plateau, les files d'attente ont augmenté d'envoyer des journaux à l'élastique sur les hôtes, et Zabbix a fleuri avec des alertes comme un arbre de Noël.
Pour éviter cela, il était logique d'écrire un script Python pour pré-créer des index. Le script fonctionne comme ceci: il trouve les indices pour aujourd'hui, extrait leurs mappages et crée de nouveaux index avec les mêmes mappages, mais pour la journée à venir. Il fonctionne sur cron, fonctionne pendant les heures où l'élastique est le moins chargé. Le script utilise la bibliothèque elasticsearch et est disponible sur
GitHub .
Pages énormes parentales transparentes
Une fois que nous avons constaté que les nœuds élastiques qui opèrent la réception des données ont commencé à se bloquer sous charge pendant les heures de pointe. Et avec des symptômes très étranges: l'utilisation de tous les cœurs de processeur tombe à zéro, mais néanmoins, le service se bloque en mémoire, écoute correctement le port, ne fait rien, ne répond pas aux demandes et tombe du cluster après un certain temps. Le service ne répond pas au redémarrage de systemctl. Seul le bon vieux kill −9 aide.
Ce n'est pas pris en compte par les outils de surveillance standard, sur les graphiques jusqu'au moment même de l'automne, l'image régulière, dans les journaux de service - est vide. Le vidage de la mémoire de la machine java à ce stade n'était également pas possible.
Mais, comme on dit, "nous sommes des professionnels, donc après un certain temps, nous avons recherché la solution sur Google". Un problème similaire a été couvert dans le fil de discussion sur
discuter.elastic.co et s'est avéré être un bogue du noyau lié aux énormes pages transparentes. Tout a été résolu en désactivant thp dans le noyau en utilisant le paquet sysfsutils.
Vérifier si vous avez activé des pages énormes transparentes est simple:
cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never]
Si [toujours] est là, vous êtes potentiellement à risque.
Conclusion
C'est le principal râteau (en fait, il y en avait, bien sûr, plus), que j'ai eu l'occasion de suivre pendant un an et demi en tant qu'administrateur du cluster Elasticsearch. J'espère que ces informations vous seront utiles lors du voyage difficile et mystérieux vers le cluster Elasticsearch idéal.
Merci pour l'illustration, Anton Gudim - il y a encore beaucoup de bien dans son
instagram .