Engineering

Erweitertes Tuning: langsame Elasticsearch-Abfragen finden und beheben

Elasticsearch ist eine extrem flexible und vielseitige Anwendung, mit der Sie Ihre Daten auf verschiedenste Arten abfragen können. Ist es Ihnen dabei jedoch schon passiert, dass eine Abfrage länger gedauert hat als Sie gehofft hatten? In verteilten Systemen wie Elasticsearch gibt es viele Faktoren, die die Leistung Ihrer Abfragen beeinflussen, inklusive externer Faktoren wie Lastenausgleichseinstellungen, Netzwerklatenz (Bandbreite, Netzwerkkarten und Treiber) usw.

In diesem Blogeintrag möchte ich Ihnen Ursachen für langsame Abfragen vorstellen und zeigen, wie Sie diese im Kontext von Elasticsearch identifizieren können. Dieser Artikel verwendet einige der gängigen Fehlerbehandlungsmethoden und setzt gute Grundkenntnisse der Funktionsweise von Elasticsearch voraus.

Häufige Ursachen für langsame Elasticsearch-Abfragen.

Bevor wir uns einige der kniffligeren Fälle ansehen, werde ich Ihnen einige der häufigsten Ursachen für langsame Abfragen zusammen mit ihren Lösungen vorstellen.

Symptom: Hohe Ressourcenverwendung im Leerlauf

Jede Shard verbraucht Ressourcen (CPU/Arbeitsspeicher). Auch ohne jegliche Indexierungs- und Suchanfragen verbrauchen die Shards durch ihr reines Vorhandensein Ressourcen im Cluster.

Problem

Der Cluster enthält zu viele Shards, und alle Abfragen werden spürbar langsam ausgeführt. Als Faustregel sollten nicht mehr als 20 nicht-eingefrorene Shards pro Knoten pro konfiguriertem Heap-GB verwenden.

Lösung

Reduzieren Sie die Shardanzahl, frieren Sie Indizes ein und/oder fügen Sie zusätzliche Knoten hinzu, um die Last verarbeiten zu können. Verwenden Sie ggf. eine Heiß-Warm-Architektur (eignet sich hervorragend für zeitbasierte Indizes) zusammen mit der Rollover-/Shrink-Funktion in Elasticsearch, um Ihre Shardanzahl effizient zu verwalten. Ein guter Ausgangspunkt für jedes Deployment ist eine angemessene Kapazitätsplanung, bei der die optimale Shardanzahl für die einzelnen Suchanwendungsfälle ermittelt wird.

Symptom: Hohe Anzahl abgelehnter Thread-Pool-Anfragen

Die Anzahl abgelehnter Anfragen im Thread Pool nimmt ständig zu. Diese Anzahl ist kumulativ seit dem letzten Clusterneustart.

GET /_cat/thread_pool/search?v&h=node_name,name,active,rejected,completed

Die Antwort sieht in etwa wie folgt aus:

node_name             name   active rejected completed
instance-0000000001   search      0       10         0
instance-0000000002   search      0       20         0
instance-0000000003   search      0       30         0

Problem

Abfragen verwenden zu viele Shards als Ziel, und die Anzahl der Kerne im Cluster wird überschritten. Dies führt dazu, dass sich die Warteschlange im Thread Pool für die Suche füllt und dass Suchanfragen abgelehnt werden. Weitere gängige Ursachen sind langsame Datenträger, die dazu führen, dass sich die Suchwarteschlange füllt, oder in manchen Fällen auch eine komplett ausgelastete CPU. 

Lösung

Verwenden Sie das Modell 1 Primär : 1 Replikat beim Erstellen von Indizes. Indexvorlagen sind ein guter Weg, um diese Einstellung bei der Indexierung zu übernehmen. (1P:1R wird ab Elasticsearch 7.0 standardmäßig verwendet). Ab Elasticsearch 5.1 können Suchaufgaben abgebrochen werden. Dies kann hilfreich sein, wenn eine langsame Abfrage in der Aufgabenverwaltungs-API angezeigt wird. Um die E/A-Leistung zu verbessern, beachten Sie unsere Speicherempfehlungen und verwenden Sie die empfohlene Hardware, um die Leistung zu optimieren.

Symptom: Hohe CPU-Auslastung und Latenz beim Indexieren

In der Metrik-Korrelation wird eine hohe CPU-Auslastung und eine hohe Latenz beim Indexieren angezeigt, wenn der Cluster überlastet ist.

Problem

Der Cluster führt aufwändige Indexierungen durch, und die Suchleistung wird beeinträchtigt.

Lösung

Wenn Sie index.refresh_ interval (die Zeit zwischen der Indexierung eines Dokuments und dem Moment, ab dem es sichtbar ist) auf einen Wert von etwa 30s erhöhen, nimmt die Indexierungsleistung normalerweise spürbar zu. Das genaue Ergebnis hängt von der Umgebung ab, probieren Sie also verschiedene Einstellungen aus. Auf diese Weise stellen Sie sicher, dass die Shards nicht jede Sekunde (Standardeinstellung) ein neues Segment erstellen müssen und dadurch überlastet werden.

Für besonders hohe Indexierungsanforderungen finden Sie Hinweise zum Optimieren von Indexierungs- und Suchleistung in unseren Empfehlungen für die Feinjustierung von Indizes.

Symptom: Höhere Latenz mit zusätzlichen Replikat-Shards

Die Abfrageleistung nimmt ab, wenn die Anzahl der Replikat-Shards erhöht wird (z. B. von 1 auf 2). Wenn mehr Daten vorhanden sind, werden die Daten früher aus dem Cache entfernt, wodurch wiederum mehr Seitenfehler im Betriebssystem auftreten.

Problem

Der Dateisystemcache ist nicht groß genug, um häufig abgefragte Teile des Index zwischenzuspeichern. Der Abfragecache von Elasticsearch implementiert eine LRU-Löschungsrichtlinie: Wenn der Cache voll ist, werden die am seltensten verwendeten Daten entfernt, um Platz für neue Daten zu schaffen.

Lösung

Reservieren Sie mindestens 50 % des physischen Arbeitsspeichers für den Dateisystemcache. Je größer der Arbeitsspeicher, desto mehr Daten können zwischengespeichert werden, insbesondere bei E/A-Problemen im Cluster. Wenn die Heapgröße korrekt konfiguriert wurde, können Sie die Suchleistung unter Umständen deutlich verbessern, indem Sie sämtlichen verbleibenden physischen Arbeitsspeicher für den Dateisystemcache freigeben.

Beispiel: Auf einem Server mit 128 GB Arbeitsspeicher sind 30 GB für den Heap reserviert und der Rest für den Dateisystemcache (manchmal auch BS-Cache genannt). In diesem Cache speichert das Betriebssystem kürzlich verwendete 4-KB-Datenblocks, um diese Daten in Zukunft direkt aus dem Arbeitsspeicher abrufen zu können und nicht jedes Mal den Datenträger zu bemühen, wenn Sie eine Datei erneut öffnen.

Neben dem Dateisystemcache verwendet Elasticsearch auch Abfrage- und Anforderungscaches, um die Suchleistung zu verbessern. Sie können diese Caches mit search-request-preference so optimieren, dass bestimmte Suchanfragen immer an dieselbe Gruppe von Shards weitergeleitet werden, anstatt zwischen den verfügbaren Kopien abzuwechseln. Auf diese Weise werden Anforderungs-, Abfrage- und Dateisystemcache noch effizienter genutzt.

Symptom: Hohe Auslastung beim Teilen von Ressourcen

Das Betriebssystem zeigt eine dauerhaft hohe Auslastung von CPU und Datenträger-E/A an. Nach dem Beenden von Drittanbieteranwendungen nimmt die Leistung zu.

Problem

Andere Prozesse (z. B. Logstash) und Elasticsearch konkurrieren um Ressourcen (CPU und/oder Datenträger-E/A).

Lösung

Vermeiden Sie es, Elasticsearch zusammen mit anderen ressourcenintensiven Anwendungen auf derselben Hardware auszuführen.

Symptom: Hohe Heap-Auslastung beim Aggregieren von Feldern mit großer Wertevielfalt.

Beim Aggregieren von Feldern mit großer Wertevielfalt (z. B. IDs, Benutzernamen, E-Mail-Adressen usw.) nimmt die Leistung spürbar ab. Bei der Analyse des Heap-Abbilds stellen Sie vermutlich fest, dass ein Großteil des Heap-Speichers von Java-Objekten mit Begriffen wie „search“, „buckets“, „aggregation“ usw. belegt wird.

Problem

Aggregationen über Felder mit hoher Kardinalität sind ressourcenintensiv, da viele Buckets abgerufen werden. Möglicherweise werden auch verschachtelte Aggregationen mit verschachtelten und/oder join-Feldern ausgeführt.

Lösung

In diesen Blogeintrag von meinem Kollegen aus dem Consulting-Team erfahren Sie, wie Sie die Leistung von Aggregationen mit hoher Kardinalität verbessern können: https://www.elastic.co/de/blog/improving-the-performance-of-high-cardinality-terms-aggregations-in-elasticsearch

Lesen Sie außerdem unsere Empfehlungen zu verschachtelten Feldern und join-Feldern, um herauszufinden, wie Sie Ihre Aggregationsleistung noch weiter verbessern können.

Vereinzelte langsame Abfragen

Wenn nur vereinzelt oder zeitweise langsame Abfragen auftreten, können Sie die Leistung möglicherweise mit unseren Empfehlungen zu den Themen Index-Tuning oder Such-Tuning verbessern. Vereinzelte langsame Abfragen korrelieren normalerweise eng mit einer oder mehreren der folgenden Überwachungsmetriken:

Mit der Adaptive Replica Selection (ARS, adaptive Replikatauswahl) bietet Elasticsearch eine weitere hilfreiche Funktion an: Der koordinierende Knoten kennt die Last auf den Datenknoten und kann jeweils die besten Shard-Kopien für die Suchausführung auswählen, um den Suchdurchsatz und die Latenz zu verbessern. ARS ist eine sehr hilfreich bei gelegentlichen Leistungsengpässen, da die Last zur Abfragezeit gleichmäßiger verteilt wird. Ab Elasticsearch 7.0 ist ARS standardmäßig aktiviert.

Dauerhaft langsame Abfragen

Falls Ihre Abfragen immer zu langsam ausgeführt werden, können Sie Features nacheinander einzeln aus der Abfrage entfernen und überprüfen, ob sich die Leistung verbessert hat. Identifizieren Sie die einfachste Abfrage, die das Leistungsproblem reproduziert, um das Problem zu isolieren und zu diagnostizieren:

  • Ist die Abfrage ohne Hervorhebung immer noch langsam?
  • Ist die Abfrage ohne Aggregationen immer noch langsam?
  • Ist die Abfrage immer noch langsam, wenn ich size auf 0 festlege? (wenn Sie size auf 0 festlegen, speichert Elasticsearch die Ergebnisse der Suchabfragen im Cache, um die Suche zu beschleunigen)

Kann ich die Abfrage mit einer der Empfehlungen zum Thema Such-Tuning verbessern?

Bei der Fehlerbehandlung sind die folgenden Punkte oft hilfreich:

  • Führen Sie eine Abfrage mit aktiviertem Profile aus und speichern Sie die Antwort.
  • Sammeln Sie die Ausgabe von nodes hot threads, während Sie die Abfrage in einer while(true)-Schleife ausführen. Auf diese Weise können Sie herausfinden, wodurch die CPU-Zeit belegt wird.
  • Erstellen Sie ein Profil der Abfrage mit dieser benutzerfreundlicheren Version der Profile API.

Falls die Abfrage aus einer Kibana-Visualisierung stammt, verwenden Sie das Visualization Spy Panel (Visualisierungsanalyse, bis Kibana-Version 6.3) oder das Dashboard Inspect Panel (Dashboardinspektion, ab Kibana-Version 6.4), um die tatsächliche Anforderung anzeigen, exportieren und zur weiteren Analyse in die Profile API importieren zu können.

Langsame oder aufwändige Abfragen identifizieren

Es kann schwierig sein, langsame oder aufwändige Abfragen zu identifizieren, wenn in einer verteilten Anwendung wie Elasticsearch verschiedene Anforderungen und Threads parallel verarbeitet werden. Noch komplizierter wird es, wenn Sie keine Kontrolle über die Benutzer haben, die aufwändige Abfragen ausführen und Ihre Clusterleistung beeinträchtigen (z. B. lange Garbage Collection-Zyklen), oder noch schlimmer, wenn OutOfMemory-Fehler (OOM) auftreten.

In Elasticsearch 7.0 führen wir eine neue Sicherungsstrategie ein. Dazu messen wir die tatsächliche Nutzung des Heap-Speichers, wenn der Arbeitsspeicher reserviert wird. Diese neue Strategie verbessert die Resilienz der Knoten gegenüber aufwändigen Abfragen, die den Cluster überlasten können. Sie ist standardmäßig aktiviert und kann mit der neuen Clustereinstellung indices.breaker.total.use_real_memory gesteuert werden.

Dieser Ansatz funktioniert jedoch nicht in allen Szenarien. Falls Ihr Problem damit nicht behoben wird, können Sie ein Heap-Abbild nach dem OOM-Absturz oder ein Heap-Abbild aus einer laufenden JVM erfassen, um die Ursache zu analysieren.

Elasticsearch bietet eine weitere Einstellung (max bucket soft limit), die den Cluster vor OOM-Situationen schützt. Diese Aggregationseinstellung für eine Bucketobergrenze beendet die Ausführung und gibt einen Fehler für die Suchanfrage zurück, wenn eine bestimmte Bucketanzahl (standardmäßig 10.000 in Version 7.0) überschritten wird (z. B. wenn mehrere Aggregationsebenen ausgeführt werden).

Um potenziell aufwändige Abfragen genauer zu identifizieren, können wir die Sicherungseinstellung (indices.breaker.request.limit) zunächst auf einen niedrigen Wert festlegen, um Abfragen zu isolieren, und den Wert anschließend langsam erhöhen, um einzelne Abfragen herauszufiltern.

Slowlogs

Sie können langsame Abfragen auch identifizieren, indem Sie slowlogs in Elasticsearch aktivieren. Slowlogs funktioniert auf der Shard-Ebene und gilt daher nur für Datenknoten. Koordinierungs- und Clientknoten sind ausgeschlossen, da sie keine Daten (Indizes/Shards) enthalten.

Mit Slowlogs können Sie beispielsweise die folgenden Fragen beantworten:

  • Wie lange hat die Abfrage gedauert?
  • Welchen Inhalt hatte der Abfragetext?

Slowlogs-Beispielausgabe:

[2019-02-11T16:47:39,882][TRACE][index.search.slowlog.query] [2g1yKIZ] [logstash-20190211][4] took[10.4s], took_millis[10459], total_hits[16160], types[], stats[], 
search_type[QUERY_THEN_FETCH], total_shards[10], source[{"size":0,"query":{"bool":{"must":[{"range":{"timestamp":{"from":1549266459837,"to":1549871259837,"include_lower":true,
"include_upper":true,"format":"epoch_millis","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":[],"excludes":[]},"stored_fields":"*","docvalue_fields":
[{"field":"timestamp","format":"date_time"},{"field":"utc_time","format":"date_time"}],"script_fields":{"hour_of_day":{"script":{"source":"doc['timestamp'].value.getHourOfDay()",
"lang":"painless"},"ignore_failure":false}},"aggregations":{"maxAgg":{"max":{"field":"bytes"}},"minAgg":{"min":{"field":"bytes"}}}}], id[]],

Komponenten der Slowlogs-Nachricht:

ElementBeschreibung
[2019-02-11T16:47:39,882]Zeitpunkt der Abfrage
[TRACE]Protokollebene
[index.search.slowlog.query]Abfragephase der Slowlog-Suche
[2g1yKIZ]Name des Knotens
[logstash-20190211]Indexname
[4]Shardnummer, auf der die Abfrage ausgeführt wurde
took[10.4s]Abfragedauer auf Shard [4]. Hinweis: Bei der Betrachtung von Slowlogs macht es keinen Sinn, die Zeiten der verschiedenen Shards zu addieren, da die Shards unter Umständen parallel ausgeführt werden.
took_millis[10459]Dauer in Millisekunden
total_hits[16160]Gesamtzahl der Treffer
search_type[QUERY_THEN_FETCH]Suchart
total_shards[10]Anzahl der Shards im Index
source[]Der ausgeführte Abfragetext

Audit-Logs

Kunden mit Gold- oder Platin-Abonnements, in denen die Elastic-Sicherheitsfunktionen enthalten sind, können die Audit-Logs aktivieren, um weitere Details zur Abfrage zu erfassen. (Jeder Benutzer kann eine 30-tägige Testversion starten, um die Elastic-Sicherheitsfunktionen auszuprobieren.) Mit den Audit-Logs können Sie beispielsweise die folgenden Fragen beantworten:

  • Wann wurde die Abfrage ausgeführt?
  • Wer hat die Abfrage ausgeführt?
  • Welchen Inhalt hatte die Abfrage?

Wir sollten die Audit-Einstellungen anpassen, da die Standardeinstellungen sehr gesprächig sind:

  1. Sicherheits-Audit-Log aktivieren: Definieren Sie xpack.security.audit.enabled: true in der Datei „elasticsearch.yml“.
  2. Log oder Index in der Sicherheits-Audit-Ausgabe aktivieren: Definieren Sie xpack.security.audit.outputs:[logfile, index] in der Datei „elasticsearch.yml“.

    Anmerkungen:
    • Die Einstellung „xpack.security.audit.outputs“ gilt nur für die Versionen 6.0 bis 6.2 und 5.x. Version 7.0 akzeptiert diese Einstellung nicht mehr und verwendet standardmäßig die JSON-Ausgabe (<Clustername>_audit.json), wenn „xpack.security.audit.enabled“ auf „true“ festgelegt ist.
    • Für die Fehlerbehandlung empfehlen wir, die Log-Dateien über den Index zu erstellen, da die Ausführlichkeit der Audit-Logs den Cluster unnötig belasten kann, wenn der Sicherheitsindex die geplante Größe überschreitet.
    • Der Audit-Modus ist sehr ausführlich und sollte daher deaktiviert werden, wenn Sie die Fehlerbehandlung abgeschlossen haben.
  3. „authentication_success“-Zugriffe zu Ihrer Ereignisliste hinzufügen: Definieren Sie xpack.security.audit.logfile.events.include: authentication_success in der Datei „elasticsearch.yml“.

    Anmerkungen:
    • Diese Einstellung ist nicht in den Standardereignissen enthalten. Diese Konfiguration überschreibt die Standardeinstellungen.
    • Falls Sie ein Ereignis hinzufügen (und nicht ersetzen) möchten, sollten Sie zunächst die vorhandene Liste der Standardereignisse angeben und die oben gezeigte Einstellung nach dem letzten Eintrag hinzufügen.
    • Anforderungstext in den Audit-Ereignissen ausgeben: Definieren Sie xpack.security.audit.logfile.events.emit_request_body: true in der Datei „elasticsearch.yml“.

Mit diesen Einstellungen können Sie die Benutzerabfrage wie folgt überwachen.

  • Benutzer: louisong
  • Zeitpunkt der Abfrage: 2019-05-01T19:26:53,554 (UTC)
  • Abfrageendpunkt: _msearch (deutet normalerweise auf eine Abfrage aus einer Kibana-Visualisierung oder einem Dashboard hin)
  • Abfragetext: ab "request.body": im folgenden Log:

    {"@timestamp":"2019-05-01T19:26:53,554", "node.id":"Z1z_64sIRcy4dW2eqyqzMw", "event.type":"rest", "event.action":"authentication_success", "user.name":"louisong", "origin.type":"rest", "origin.address":"127.0.0.1:51426", "realm":"default_native", "url.path":"/_msearch", "url.query":"rest_total_hits_as_int=true&ignore_throttled=true", "request.method":"POST", "request.body":"{\"index\":\"*\",\"ignore_unavailable\":true,\"preference\":1556709820160}\n{\"aggs\":{\"2\":{\"terms\":{\"field\":\"actions\",\"size\":5,\"order\":{\"_count\":\"desc\"},\"missing\":\"__missing__\"}}},\"size\":0,\"_source\":{\"excludes\":[]},\"stored_fields\":[\"*\"],\"script_fields\":{},\"docvalue_fields\":[{\"field\":\"access_token.user_token.expiration_time\",\"format\":\"date_time\"},{\"field\":\"canvas-workpad.@created\",\"format\":\"date_time\"},{\"field\":\"canvas-workpad.@timestamp\",\"format\":\"date_time\"},{\"field\":\"creation_time\",\"format\":\"date_time\"},{\"field\":\"expiration_time\",\"format\":\"date_time\"},{\"field\":\"maps-telemetry.timeCaptured\",\"format\":\"date_time\"},{\"field\":\"task.runAt\",\"format\":\"date_time\"},{\"field\":\"task.scheduledAt\",\"format\":\"date_time\"},{\"field\":\"updated_at\",\"format\":\"date_time\"},{\"field\":\"url.accessDate\",\"format\":\"date_time\"},{\"field\":\"url.createDate\",\"format\":\"date_time\"}],\"query\":{\"bool\":{\"must\":[{\"range\":{\"canvas-workpad.@timestamp\":{\"format\":\"strict_date_optional_time\",\"gte\":\"2019-05-01T11:11:53.498Z\",\"lte\":\"2019-05-01T11:26:53.498Z\"}}}],\"filter\":[{\"match_all\":{}},{\"match_all\":{}}],\"should\":[],\"must_not\":[]}},\"timeout\":\"30000ms\"}\n", "request.id":"qrktsPxyST2nVh29GG7tog"}
        

    Fazit

    In diesem Artikel habe ich Ihnen gängige Ursachen für langsame Abfragen und mögliche Lösungsmaßnahmen vorgestellt. Außerdem haben wir verschiedene Methoden behandelt, mit denen wir dauerhaft oder vereinzelt auftretende langsame Abfragen identifizieren können. Langsame Abfragen sind oft ein Symptom für allgemeine Leistungsprobleme im Cluster, die behoben werden sollten.

    Elasticsearch bemüht sich fortlaufend darum, die Abfragezeiten zu verbessern und die Leistung Ihrer Abfragen in zukünftigen Versionen zu steigern. Hoffentlich hilft Ihnen dieser Artikel bei der Behebung von langsamen Abfragen. Falls Sie Fragen haben, können Sie jederzeit an unserem Elasticsearch-Diskussionsforum teilnehmen. Happy Searching!