Verwalten des Elasticsearch-Arbeitsspeichers und Beheben von Problemen

Hallo! Mit der Erweiterung unseres Elasticsearch Service-Cloud-Angebots und dem automatisierten Onboarding ist der Elastic Stack jetzt nicht mehr nur für Full-Ops-Teams, sondern auch für Data Engineers, Sicherheitsteams und Consultants interessant geworden. Als Elastic-Support-Engineer finde ich die Ausweitung des Zielpublikums auf Nutzer:innen aus einem breiterem Berufsspektrum und eine größere Palette von Anwendungsfällen richtig gut. 

Durch den größer gewordenen Nutzerkreis erreichen mich zunehmend Fragen zur Verwaltung der Ressourcenzuweisung, insbesondere zum geheimnisvollen Shard-Heap-Verhältnis und zur Vermeidung der Auslösung von Sicherungen (Circuit Breakers). Das kann ich absolut nachvollziehen! Als ich damit begann, mich mit dem Elastic Stack zu beschäftigen, hatte ich dieselben Fragen. Damals hatte ich zum ersten Mal mit dem Verwalten von Java-Heaps und Zeitreihen-Datenbank-Shards und mit der Skalierung meiner eigenen Infrastruktur zu tun.

Als ich Teil des Elastic-Teams wurde, fand ich es toll, dass es neben der Dokumentation Blogs und Tutorials gab – so konnte ich mich schnell in das Thema einarbeiten. Im ersten Monat fiel es mir aber schwer, mein theoretisches Wissen und die Fehlermeldungen, die ich über meine Ticket-Queue reinbekam, vernünftig in Einklang zu bringen. Irgendwann begriff ich dann aber, was andere Support-Engineers schon vor mir verstanden haben: Viele gemeldete Fehler sind lediglich Symptome von Zuweisungsproblemen und im Grunde reichten so um die sieben Links, um so gut wie jede:n Nutzer:in schnell wieder in die Ressourcenzuweisungsspur zu bekommen.

In den folgenden Abschnitten werde ich Ihnen aus meiner Sicht als Support-Engineer zeigen, wo Sie als Nutzer:in Informationen zur Theorie des Zuweisungsmanagements finden, welche Symptome wir am häufigsten feststellen und wohin wir Nutzer:innen leiten, damit sie ihre Konfigurationen so ändern können, dass ihre Probleme mit der Ressourcenzuweisung gelöst werden.

Theorie

Da Elasticsearch eine Java-Anwendung ist, muss ihr etwas logischer Arbeitsspeicher (Heap) aus dem physischen Arbeitsspeicher des Systems zugewiesen werden. Sie sollten dabei bis zur Hälfte des physischen RAM, maximal jedoch 32 GB zuweisen. Wird eine höhere Heap-Nutzung festgelegt, ist das in der Regel eine Folge aufwändiger Abfragen und größerer Datenspeicher. Der Standardwert für die Sicherung auf übergeordneter Ebene (Parent Circuit Breaker) liegt bei 95 %, wir empfehlen aber, die Ressourcen einmalig auf 85 % zu skalieren

Ausführliche Informationen finden Sie in den folgenden Übersichtsartikeln:

Konfiguration

Bei Verwendung der Standardeinstellungen von Elasticsearch wird die Größe des JVM-Heaps automatisch anhand der Rolle des Knotens und des Gesamtarbeitsspeichers festgelegt. Bei Bedarf haben Sie aber drei Möglichkeiten, die Heap-Größe direkt zu konfigurieren:

1. Direkt in der config > jvm.options-Datei Ihrer lokalen Elasticsearch-Dateien

## 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. Als Elasticsearch-Umgebungsvariable in 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=-Xms512m -Xmx512m"
- discovery.type=single-node
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200

3. Über unseren Elasticsearch Service > „Deployment“ > Ansicht „Edit“. Hinweis: Mit dem Schieberegler weisen Sie physischen Arbeitsspeicher zu. Etwa die Hälfte davon wird dem Heap zugewiesen.

blog-elasticsearch-memory.png

Beseitigen von Problemen

Wenn Sie derzeit Probleme mit der Performance Ihres Clusters haben, liegt es wahrscheinlich an den üblichen Verdächtigen:

  • Probleme mit der Konfiguration: Oversharding, keine ILM-Richtlinie
  • Volumeninduziert: Hohes Anfragetempo / hohe Anfragenlast, sich überlappende aufwändige Abfragen / Schreibvorgänge

Alle folgenden cURL-/API-Anfragen können in der API-Konsole von Elasticsearch Service, als cURL, die auf die Elasticsearch-API verweist, oder in Kibana unter „Dev Tools“ erfolgen.

Oversharding

Datenindizes werden in Sub-Shards gespeichert, die für die Wartung und bei Such-/Schreibanfragen den Heap verwenden. Die Shard-Größe sollte maximal 50 GB betragen und für die Bestimmung ihrer Höchstzahl kann diese Gleichung herangezogen werden:

shards = sum(nodes.max_heap) * 20

Für das Elasticsearch Service-Beispiel oben mit 8 GB physischem Speicher über zwei Zonen (für insgesamt zwei Knoten) ergibt sich daraus Folgendes:

#node.max_heap
8GB of physical memory / 2 = 4GB of heap
#sum(nodes.max_heap)
4GB of heap * 2 nodes = 8GB
#max shards
8GB * 20
160

Vergleichen Sie dies dann entweder mit _cat/allocation

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

oder mit _cluster/health

GET /de/_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
}

Dieses Deployment hat also 82 der empfohlenen Maximalzahl von 160 Shards. Wäre die Zahl höher als die empfohlene Zahl, können die in den nächsten beiden Abschnitten beschriebenen Symptome auftreten (siehe unten).

Wenn eine der Shards außerhalb active_shards oder active_primary_shards > 0 meldet, haben Sie eine wichtige Konfigurationsursache für Performance-Probleme ausgemacht.

Falls aus diesem Grund ein Problem gemeldet wird, handelt es sich dabei zumeist um unassigned_shards > 0. Wenn es sich bei diesen Shards um primäre Shards handelt, meldet Ihr Cluster dies als status:red. Sind jedoch nur Replikate betroffen, wird status:yellow gemeldet. (Aus diesem Grund ist es wichtig, die Zahl der Replikate für Indizes festzulegen, damit im Falle eines Problems der Cluster wiederhergestellt werden kann, ohne dass Daten verloren gehen.)

Nehmen wir an, wir haben eine status:yellow-Meldung mit nur einer nicht zugewiesenen Shard. Um dies zu untersuchen, sehen wir uns über _cat/shards an, bei welcher Index-Shard das Problem besteht.

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

Es geht also um unsere Nicht-System-Index-Logs, bei denen es eine nicht zugewiesene Replikat-Shard gibt. Um den Grund für das Ungemach festzustellen, führen wir _cluster/allocation/explain aus (kleiner Tipp vom Support-Experten: Genau das tun wir auch, wenn Sie sich an den Support wenden.)

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]"
}]}]}

Diese Fehlermeldung verweist auf data_hot, was Teil einer Index-Lifecycle-Management(ILM)-Richtlinie ist und darauf hindeutet, dass unsere ILM-Richtlinie nicht mit unseren aktuellen Indexeinstellungen übereinstimmt. In diesem Fall ist der Grund für diesen Fehler, dass wir eine Heiß-Warm-ILM-Richtlinie ohne entsprechende Heiß-Warm-Knoten eingerichtet haben. (Ich musste irgendwie dafür sorgen, dass etwas garantiert fehlschlägt. Leute, ich muss mir hier Fehlerbeispiele aus den Fingern saugen – so weit ist es schon gekommen! 😂)

Am Rande sei erwähnt: Wenn dieser Befehl ausgeführt wird, ohne dass es nicht zugewiesene Shards gibt, wird ein 400-Fehler gemeldet, dem zufolgekeine nicht zugewiesenen Shards gefunden werden konnten, die zu erklären wären, weil es keine zu meldenden Fehler gibt.

Wenn es einen Grund gibt, der nichts mit der Logik zu tun hat (z. B. einen temporären Netzwerkfehler wie node left cluster during allocation), können Sie die überaus praktische Elastic-Anfrage _cluster/reroute verwenden.

POST /de/_cluster/reroute

Ohne weitere Anpassungen startet diese Anfrage einen asynchronen Hintergrundprozess, der versucht, alle derzeit unzugewiesenen Shards (state:UNASSIGNED) zuzuweisen. (Machen Sie es nicht wie ich und warten Sie, bis die Anfrage abgeschlossen ist, bevor Sie sich an die Entwickler:innen wenden. Ich dachte, sie würde sofort, gleichzeitig und gerade rechtzeitig eskaliert, sodass diese sagen könnten, es sei alles in Ordnung, obwohl nichts mehr in Ordnung war.)

Sicherungen

Wenn Sie Ihre Heap-Zuweisung ausschöpfen, kann dies dazu führen, dass Anfragen an Ihren Cluster zu einer Zeitüberschreitung oder einem Fehler führen und dass Ihr Cluster häufig mit Ausnahmen wegen ausgelöster Sicherungen (Circuit Breakers) zu tun hat. Das Auslösen dieser Sicherungen führt zu elasticsearch.log-Ereignissen wie den folgenden:

Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [] 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]

Um dies zu untersuchen, müssen Sie sich Ihre heap.percent-Werte ansehen. Verwenden Sie dazu entweder _cat/nodes

GET /de/_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

oder gehen Sie zu Kibana > „Stack Monitoring“, sofern bereits aktiviert.

blog-elasticsearch-memory-2.png

Wenn Sie sich vergewissert haben, dass die für die Arbeitsspeicher-Sicherungen festgelegten Werte erreicht wurden, sollten Sie darüber nachdenken, die Größe Ihres Heaps vorübergehend zu erhöhen, um sich eine Atempause für Ihre Untersuchungen zu verschaffen. Bei der Suche nach der Ursache empfiehlt es sich, sich die Cluster-Proxy-Logs oder elasticsearch.log anzusehen und dort zu prüfen, welche aufeinanderfolgenden Ereignisse vorausgegangen sind. Suchen Sie dabei nach

  • aufwändigen Abfragen, insbesondere:
    • Aggregationen mit hohen Bucket-Zahlen
      •  Ich kam mir so dumm vor, als mir dämmerte, dass Suchen vorübergehend einen bestimmten Teil des Heaps zuweisen, bevor sie die Abfrage auf der Grundlage der Suchgröße oder der Bucket-Dimensionen ausführen, sodass eine Einstellung wie „10.000.000“ meinem Ops-Team wirklich Kopfzerbrechen bereitet haben musste.
    • nicht-optimierte Mappings
      • Außerdem kam ich mir dumm vor, weil ich dachte, dass es beim hierarchischen Reporting einfacher wäre zu suchen, als wenn die Daten alle „geflattet“ wären (ist es nicht!).
  • Anfragevolumen/-tempo: in der Regel Batch- oder asynchrone Abfragen

Zeit zu skalieren

Wenn die Werte für das Auslösen der Sicherungen nicht zum ersten Mal erreicht werden oder wenn Sie vermuten, dass das zum ständigen Problem wird (weil z. B. dauerhaft 85 % erreicht werden und es daher an der Zeit ist, sich mit dem Skalieren der Ressourcen zu beschäftigen), sollten Sie sich genauer mit dem JVM-Arbeitsspeicherdruck als Ihrem langfristigen Heap-Indikator beschäftigen. Prüfen lässt sich dieser unter Elasticsearch Service > „Deployment“.

blog-elasticsearch-memory-3.png

Sie können den Druck auch über _nodes/stats ermitteln,

GET /de/_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
}}}}}}}

wobei

JVM Memory Pressure = used_in_bytes / max_in_bytes

Ein mögliches Symptom dafür ist eine hohe Frequenz und lange Dauer von Garbage-Collector-Ereignissen (gc-Ereignissen) in 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]

Wenn sich dies bestätigt, müssen Sie entweder die Skalierung Ihres Clusters oder die Verringerung der Anforderungen an den Cluster in Betracht ziehen. Dabei sollten Sie Folgendes untersuchen/erwägen:

Fazit

Puh! Nach dem, was ich beim Elastic Support so erlebe, ist das die Liste der häufigsten Nutzertickets: nicht zugewiesene Shards, ein unausgewogenes Shard-Heap-Verhältnis, Auslösen von Sicherungen, hohe Garbage-Collection-Aktivität und Zuweisungsfehler. All diese Probleme sind Symptome einer mangelnden Verwaltung der Zuweisung von Kernressurcen. Ich hoffe, Sie haben jetzt die notwendigen theoretischen Kenntnisse und wissen auch, was Sie tun müssen, um diese Probleme zu lösen.

Sollten Sie dennoch an einer Stelle nicht weiterkommen, können Sie sich gern an uns wenden. Wir helfen Ihnen gern! Sie können uns über Elastic Discuss, Elastic Community Slack, Consulting, Training und den Support kontaktieren.

Ein Hoch auf unsere Fähigkeit, die Ressourcenzuweisung von Elastic Stack als Nicht-Ops selbst zu verwalten (liebe Ops-Leute, das geht nicht gegen euch)!