„Eine ausgebildete Person tritt auch auf einen Rechen.
Aber auf der anderen Seite, wo der Stift ist. “Elasticsearch ist ein großartiges Werkzeug, aber jedes Werkzeug erfordert nicht nur
Optimierung und
Wartung , sondern auch Liebe zum Detail. Einige sind unbedeutend und liegen an der Oberfläche, während andere so tief verborgen sind, dass die Suche mehr als einen Tag dauert, nicht ein Dutzend Tassen Kaffee und nicht einen Kilometer Nerven. In diesem Artikel erzähle ich Ihnen von neun wunderbaren Rechen in den elastischen Einstellungen, auf die ich getreten bin.
Ich werde den Rechen in absteigender Reihenfolge der Beweise anordnen. Von denen, die beim Aufbau und Eintritt in einen Cluster im Produktionszustand vorausgesehen und umgangen werden können, bis zu sehr seltsamen, die die meiste Erfahrung bringen (und Sterne in den Augen).
Datenknoten müssen gleich sein
"Der Cluster läuft mit der Geschwindigkeit des langsamsten Datenknotens" - ein qualvolles Axiom. Es gibt jedoch noch einen weiteren offensichtlichen Punkt, der nicht mit der Leistung zusammenhängt: Der Elastiker denkt nicht im Speicherplatz, sondern in Shards und versucht, sie gleichmäßig auf die Datenknoten zu verteilen. Wenn einige der Datenknoten mehr Speicherplatz als andere haben, ist es sinnlos, untätig zu bleiben.
Deprecation.log
Es kann vorkommen, dass jemand nicht die modernsten Mittel zum Senden von Daten an das Gummiband verwendet, wodurch der Inhaltstyp bei der Ausführung von Abfragen nicht festgelegt werden kann. In dieser Liste zum Beispiel heka oder wenn die Protokolle die Geräte mit ihren eingebauten Mitteln verlassen). In diesem Fall Verfall. Das Protokoll beginnt mit alarmierender Geschwindigkeit zu wachsen, und für jede Anforderung werden die folgenden Zeilen angezeigt:
[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.
Anfragen kommen durchschnittlich alle 5-10 ms - und jedes Mal, wenn eine neue Zeile zum Protokoll hinzugefügt wird. Dies wirkt sich negativ auf die Leistung des Festplattensubsystems aus und erhöht iowait. Deprecation.log kann deaktiviert werden, ist aber nicht sinnvoll. Um elastische Protokolle darin zu sammeln, aber nicht zu verschmutzen, deaktiviere ich nur Protokolle der Klasse oedrRestController.
Fügen Sie dazu logs4j2.properties die folgende Konstruktion hinzu:
logger.restcontroller.name = org.elasticsearch.deprecation.rest.RestController logger.restcontroller.level = error
Dadurch werden die Protokolle dieser Klasse auf die Fehlerstufe angehoben, und sie fallen nicht mehr in deprecation.log.
.kibana
Wie sieht ein typischer Cluster-Installationsprozess aus? Wir setzen die Knoten, kombinieren sie zu einem Cluster, setzen das X-Pack (wer es braucht) und natürlich Kibana. Wir starten, überprüfen, ob alles funktioniert und Kibana den Cluster sieht, und konfigurieren weiter. Das Problem ist, dass in einem frisch installierten Cluster die Standardvorlage ungefähr so aussieht:
{ "default": { "order": 0, "template": "*", "settings": { "number_of_shards": "1", "number_of_replicas": "0" } }, "mappings": {}, "aliases": {} }
Der .kibana-Index, in dem alle Einstellungen gespeichert sind, wird in einer einzigen Kopie erstellt.
Es gab einmal einen Fall, in dem aufgrund eines Hardwarefehlers einer der Datenknoten im Cluster getötet wurde. Es kam schnell zu einem konsistenten Zustand und erzeugte Replikate von Shards von benachbarten Datenknoten, aber glücklicherweise befand sich auf diesem Datenknoten der einzige Shard mit dem .kibana-Index. Die Situation ist eine Pattsituation - der Cluster ist in Betrieb, in einem funktionierenden Zustand, und Kibana befindet sich in einem roten Status, und mein Telefon ist von Anrufen von Mitarbeitern zerrissen, die ihre Protokolle dringend benötigen.
All dies wird einfach gelöst. Bisher ist nichts gefallen:
XPUT .kibana/_settings { "index": { "number_of_replicas": "<__>" } }
XMX / XMS
In der
Dokumentation steht zu Recht „Nicht mehr als 32 GB“. Es ist aber auch richtig, dass Sie nicht in den Diensteinstellungen installieren müssen
-Xms32g -Xmx32g
Weil es bereits mehr als 32 Gigabyte sind und wir hier auf eine interessante Nuance von Java stoßen, das mit Speicher arbeitet. Ab einem bestimmten Grenzwert verwendet Java keine komprimierten Zeiger mehr und verbraucht unangemessen viel Speicher. Es ist sehr einfach zu überprüfen, ob komprimierte Zeiger einen Java-Computer verwenden, auf dem Elasticsearch ausgeführt wird. Wir schauen im Serviceprotokoll nach:
[2018-07-29T15:04:22,041][INFO][oeeNodeEnvironment][log-elastic-hot3] heap size [31.6gb], compressed ordinary object pointers [true]
Die Speichermenge, die nicht überschritten werden darf, hängt unter anderem von der verwendeten Java-Version ab. Informationen zur Berechnung des genauen Volumens in Ihrem Fall finden Sie in der
Dokumentation .
Jetzt habe ich auf allen Datenknoten des Gummibandes installiert:
-Xms32766m -Xmx32766m
Es scheint eine banale Tatsache zu sein, und die Dokumentation ist gut beschrieben, aber ich stoße regelmäßig auf Elasticsearch-Installationen, bei denen ich diesen Punkt verpasst habe, und Xms / Xmx sind auf 32 g eingestellt.
/ var / lib / elasticsearch
Dies ist der Standardpfad zum Speichern von Daten in Elasticsearch. yml:
path.data: /var/lib/elasticsearch
Dort mounte ich normalerweise ein großes RAID-Array, und hier ist der Grund: Wir geben ES verschiedene Möglichkeiten zum Speichern von Daten an, zum Beispiel wie folgt:
path.data: /var/lib/elasticsearch/data1, /var/lib/elasticsearch/data2
In data1 und data2 sind verschiedene Festplatten oder RAID-Arrays gemountet. Das Gummiband gleicht sich jedoch nicht aus und verteilt die Last nicht auf diese Pfade. Zuerst füllt er einen Abschnitt aus und beginnt dann, in einen anderen zu schreiben, damit die Belastung des Speichers ungleichmäßig ist. Da ich das wusste, traf ich eine eindeutige Entscheidung - ich kombinierte alle Festplatten in RAID0 / 1 und mounte sie in den in path.data angegebenen Pfad.
verfügbare_Prozessoren
Und nein, ich meine jetzt nicht Prozessoren auf Aufnahmeknoten. Wenn Sie sich die Eigenschaften eines laufenden Knotens (über die _nodes-API) ansehen, sehen Sie Folgendes:
"os". { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-87-generic", "available_processors": 28, "allocated_processors": 28 }
Es ist ersichtlich, dass der Knoten auf einem Host mit 28 Kernen ausgeführt wird und das Gummiband seine Anzahl korrekt bestimmt und auf allen gestartet hat. Aber wenn es mehr als 32 Kerne gibt, passiert es manchmal so:
"os": { "refresh_interval_in_millis": 1000, "name": "Linux", "arch": "amd64", "version": "4.4.0-116-generic", "available_processors": 72, "allocated_processors": 32 }
Sie müssen die Anzahl der Prozessoren erzwingen, die dem Dienst zur Verfügung stehen - dies wirkt sich positiv auf die Leistung des Knotens aus.
processors: 72
thread_pool.bulk.queue_size
Im Abschnitt thread_pool.bulk.rejected des letzten
Artikels gab es eine solche Metrik - die Anzahl der Fehler bei Anforderungen zum Hinzufügen von Daten.
Ich habe geschrieben, dass das Wachstum dieses Indikators ein sehr schlechtes Zeichen ist, und die Entwickler empfehlen, keine Thread-Pools einzurichten, sondern neue Knoten zum Cluster hinzuzufügen - angeblich löst dies Leistungsprobleme. Aber die Regeln werden benötigt, um sie manchmal zu brechen. Und es ist nicht immer möglich, "das Problem mit Eisen zu lösen". Eine der Maßnahmen zur Bekämpfung von Fehlern bei Massenanfragen besteht darin, die Größe dieser Warteschlange zu erhöhen.
Standardmäßig sehen die Warteschlangeneinstellungen folgendermaßen aus:
"thread_pool": { "bulk": { "type": "fixed", "min": 28, "max": 28, "queue_size": 200 } }
Der Algorithmus ist wie folgt:
- Wir sammeln Statistiken über die durchschnittliche Warteschlangengröße während des Tages (der Sofortwert wird in thread_pool.bulk.queue gespeichert).
- Erhöhen Sie queue_size vorsichtig auf Größen, die geringfügig größer als die durchschnittliche Größe der aktiven Warteschlange sind, da ein Fehler auftritt, wenn er überschritten wird.
- Wir vergrößern den Pool - dies ist nicht notwendig, aber akzeptabel.
Fügen Sie dazu den Host-Einstellungen Folgendes hinzu (Sie haben natürlich Ihre eigenen Werte):
thread_pool.bulk.size: 32 thread_pool.bulk.queue_size: 500
Und nach dem Neustart des Knotens werden wir definitiv die Last, die E / A und den Speicherverbrauch überwachen. und alles, was möglich ist, um die Einstellungen bei Bedarf zurückzusetzen.
Wichtig: Diese Einstellungen sind nur auf Knoten sinnvoll, die neue Daten empfangen.Vorläufige Indexerstellung
Wie ich im ersten
Artikel der Serie sagte, verwenden wir Elasticsearch, um die Protokolle aller Microservices zu speichern. Das Endergebnis ist einfach: Ein Index speichert die Protokolle einer Komponente an einem Tag.
Daraus folgt, dass jeden Tag neue Indizes durch die Anzahl der Mikrodienste erstellt werden - daher fiel das Gummiband früher jede Nacht für etwa 8 Minuten in den Clinch, während hundert neue Indizes erstellt wurden, mehrere hundert neue Shards, der Zeitplan für das Laden der Festplatte „ins Regal“ ging und die Warteschlangen wuchsen Zabbix blühte mit Warnungen wie ein Weihnachtsbaum.
Um dies zu vermeiden, war es normal, ein Python-Skript zu schreiben, um Indizes vorab zu erstellen. Das Skript funktioniert folgendermaßen: Es findet die Indizes für heute, extrahiert ihre Zuordnungen und erstellt neue Indizes mit denselben Zuordnungen, jedoch für den kommenden Tag. Es läuft auf Cron, läuft in den Stunden, in denen der Elastic am wenigsten belastet ist. Das Skript verwendet die Elasticsearch-Bibliothek und ist auf
GitHub verfügbar.
Transparente übergeordnete riesige Seiten
Als wir feststellten, dass die elastischen Knoten, die den Datenempfang bedienen, während der Stoßzeiten unter Last zu hängen begannen. Und mit sehr seltsamen Symptomen: Die Verwendung aller Prozessorkerne sinkt auf Null, aber der Dienst bleibt im Speicher hängen, hört ordnungsgemäß auf den Port, tut nichts, reagiert nicht auf Anforderungen und fällt nach einiger Zeit aus dem Cluster heraus. Der Dienst reagiert nicht auf einen Neustart des Systems. Nur der gute alte Kill −9 hilft.
Dies wird von Standardüberwachungstools in den Diagrammen erst im Moment des Sturzes erfasst, in dem das reguläre Bild in den Serviceprotokollen leer ist. Der Speicherauszug der Java-Maschine war zu diesem Zeitpunkt ebenfalls nicht möglich.
Aber wie sie sagen: "Wir sind Profis, also haben wir nach einiger Zeit die Lösung gegoogelt." Ein ähnliches Problem wurde im Thread auf "
Diskussion.elastic.co" behandelt und stellte sich als Kernel-Fehler heraus, der mit transparenten großen Seiten zusammenhängt. Alles wurde gelöst, indem thp im Kernel mit dem sysfsutils-Paket deaktiviert wurde.
Es ist einfach zu überprüfen, ob transparente große Seiten aktiviert sind:
cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never]
Wenn [immer] da ist, sind Sie möglicherweise gefährdet.
Fazit
Dies ist der Hauptrechen (tatsächlich gab es natürlich noch mehr), den ich als Administrator des Elasticsearch-Clusters anderthalb Jahre lang betreten habe. Ich hoffe, diese Informationen sind nützlich auf dem schwierigen und mysteriösen Weg zum idealen Elasticsearch-Cluster.
Vielen Dank für die Illustration, Anton Gudim - in seinem
Instagram steckt noch viel Gutes.