03 November 2015 Engineering

Überlegungen zur Indexierungsperformance in Elasticsearch 2.0

Von Michael McCandless

Vor etwas mehr als einem Jahr beschrieb ich, wie man den Indexierungsdurchsatz mit Elasticsearch maximiert. Seitdem hat sich vieles geändert. Darum beschreibe ich hier die Änderungen, die die Indexierungsleistung in Elasticsearch 2.0.0 betreffen.

small-auto-throttle.jpg

Store throttling ist jetzt automatisch

Vor 2.0.0 drosselte Elasticsearch laufende Merges mit einer festen Geschwindigkeit (standardmäßig 20 MB/Sek.). Das war jedoch in vielen Situationen viel zu langsam und führte dazu, dass Merges in Verzug gerieten und in Folge Indexdrosselung auftrat.

Ab 2.0.0 nutzt Elasticsearch adaptive IO-Drosselung bei Merges: Wenn Merges in Rückstand sind, wird die erlaubte IO-Rate erhöht. Wenn Merges mithalten, wird sie gesenkt. Dies bedeutet, dass ein seltener aber großer Merge bei geringem Indexierungsdurchsatz nicht alle verfügbaren IO auf dem betroffenen Node beanspruchen sollte. So wird der Einfluss auf laufende Suchen oder Indexierung minimiert. 

Bei hohem Indexierungsdurchsatz jedoch wird die erlaubte Merges-IO erhöht, um sich der laufenden Indexierung anzupassen.

Das sind gute Neuigkeiten!  Es bedeutet, dass sie keine Drosselungseinstellungen ändern müssen: Nutzen Sie einfach die Standardeinstellugnen.

Mehrere path.data

Die Verwendung mehrerer IO-Devices (bei Angabe mehrerer path.data-Pfade), um die Shards auf Ihrem Node zu halten, ist nützlich, um den Gesamtspeicherplatz und die IO-Leistung zu erhöhen – sollte dies ein Engpass bei der Nutzung von Elasticsearch sein.

Es gibt eine wichtige Änderung in der Art, wie Elasticsearch die IO-Last auf mehrere Pfade verteilt: Vorher wurde jede Indexdatei (durch Lucene erzeugte Dateien) zu dem optimalsten Pfad (standardmäßig: mit geringstem Datenbestand) gesendet, aber dieser Wechsel findet jetzt stattdessen pro Shard statt.  Wenn ein Shard dem Node zugewiesen wird, entscheidet der Node, welcher Pfad alle Dateien für diesen Shard enthalten soll.

Dies verbessert die Situation bei Ausfall der IO-Devices: Wenn eins Ihrer IO-Devices abstürzt, verlieren Sie nur die darauf enthaltenen Shards. Wohingegen Sie vor 2.0.0 jeden Shard verloren haben, der mindestens eine Datei auf dem betroffenen Device hatte (was typischerweise nahezu alle Shards auf diesem Node bedeutete).

Beachten Sie, dass auch ein Software RAID 0 keine gute Wahl ist, da Sie alle Shards auf diesem Node verlieren würden, wenn ein Gerät ausfällt, daher sind mehrere path.data ratsam.

Sie sollten noch mindestens eine Replika für Ihre Indizes haben, damit Sie die verlorenen Shards ohne Datenverlust wiederherstellen können.

Die Auto-ID-Optimierung wurde entfernt

Vorher optimierte Elasticsearch den Auto-ID-Fall (wenn Sie keine eigene ID für jedes einzelne indizierte Dokument angegeben hatten), um append-only Lucene API „unter der Haube“ zu verwenden. Doch das erwies sich in Fehlerfällen als problematisch, weshalb wir es entfernt haben

Wir haben zudem die ID-Lookup-Leistung sehr verbessert, sodass diese Optimierung nicht mehr so wichtig war. Dies erlaubte es uns, die Bloom-Filter komplett zu entfernen.Einerseits trugen sie nicht viel zur Performance-Steigerung bei ID-Lookups bei und andererseits verbrauchten sie zu viel Heap-Speicher.

Zu guter Letzt verwendet Elasticsearch ab 1.4.0 jetzt Flake-IDs, um seine IDs zu generieren und eine bessere Lookup-Leistung im Gegensatz zu den früheren UUIDs zu erzielen.

Dies bedeutet, dass Sie Ihr eigenes ID-Feld ohne Leistungseinbuße aufgrund des jetzt entfernten Auto-ID-Handling frei wählen können. Aber vergessen Sie nicht, dass sich Ihre Wahl der ID-Feld-Werte auf die Indexierungsleistung auswirkt.

Weitere Änderungen im Bereich der Indexierung...

Zusätzlich zu diesen Änderungen gibt es viele weitere Indexierungsänderungen in 2.0 wie beispielsweise: standardmäßige Aktivierung von Doc Values (statt CPU- und Heap-intensive Felddaten während der Suchzeit zu verwenden), die Verschiebung der gefährlichen delete-by-query API aus der Core-API in ein sicheres Plugin auf Basis der Bulk-API, bessere Kontrolle über höhere Speicherfeld-Komprimierung während der Indexierung, bessere Komprimierung der Doc Values und Norms, reduzierung von Heap, das bei Merges benutzt wird, sowie einige Verbesserungen in der Ausfallsicherheit wiez das Erkennen vorhandener Index Corruptions beim Merging.

Wenn Sie eine detaillierte Ausgabe der Lucene-Vorgänge während der Indexierung erhalten möchten, dann fügen Sie index.engine.lucene.iw: TRACE in Ihr logging.yml, hinzu. Seien Sie vorgewarnt, dass diese Option zum massiven Output führt.

Die durch nächtliche Indexierung erzeugten Messdaten und Charts zeigen, dass wir uns mit unseren Standards über Zeit auf dem richtigen Weg sind: die Dokumente/Sek. und Segmentanzahl sehen entsprechend gut aus.