Speichervergleiche zwischen Solr 3x und trunk
Oder: „Trunk kann etwa 1/3 des Speicherbedarfs von 3.x nutzen“. Bitte beachten Sie, dass bei der Erstellung dieser Tests darauf…
Oder: „Trunk kann etwa 1/3 des Speicherbedarfs von 3.x nutzen“.
Bitte beachten Sie, dass bei der Erstellung dieser Tests darauf geachtet wurde, die Unterschiede hervorzuheben. Ich habe mich zum Beispiel für eine Sortierung nach Strings entschieden, weil ich wusste, dass dies ein Bereich ist, der die Verbesserungen hervorhebt. Trotzdem bin ich ziemlich beeindruckt.
Wenn Sie die ganzen Einrichtungsinformationen überspringen möchten, gehen Sie zum Abschnitt „Messergebnisse“.
Schätzung der Hardwareanforderungen
Bei Lucid werden wir oft gefragt: „Wie viel Hardware benötige ich bei X Dokumenten und Y QPS“? Eine ähnliche Frage lautet: „Wie viele Dokumente passen auf ein Gerät mit der Größe Z?“.
Das sind durchaus berechtigte Fragen, die ich gerne selbst beantwortet haben möchte. Grant Ingersoll hat eine Kalkulationstabelle erstellt, mit der Sie den Speicherbedarf abschätzen können: Grant’s Memory Estimator. Wenn Sie sich diese Tabelle ansehen, werden Sie einige der Probleme erkennen. Es gibt einfach zu viele Variablen, die Sie im Voraus kennen müssen. Oft wollen die Hardwareentwickler eine grobe Schätzung, bevor die Suchanforderungen feststehen, was die Sache noch schwieriger macht.
In gewisser Weise ist das wie die Frage „Wie groß ist ein ‚Java‘-Programm?“. Die Antwort lautet immer: „Nun, was soll es denn _tun_?“. Hier bei Lucid sind wir ziemlich gut darin geworden, zu antworten: „Sie müssen Prototypen erstellen“. Das ist keine Ausrede. Ich persönlich habe mindestens dreimal versucht, Richtlinien für diese Fragen für den internen Gebrauch zu erstellen. Normalerweise brauche ich etwa 1/2 Stunde, um mich daran zu erinnern, warum ich meine früheren Versuche aufgegeben habe. Ich bekomme schnell Schätzungen wie „Sie brauchen zwischen 1 Laptop und 3 Supercomputern“ – was völlig nutzlos ist. Hey, ich werde besser. Ich brauche immer weniger Zeit, um aufzugeben ;). Wenn Sie aus mehreren Variablen Bereiche bilden, wird die Spanne riesig. Variablen wie:
- Sortieren (wie viele Felder? Wie viele eindeutige Begriffe pro Feld?)
- Facettierung (wie viele Felder? Wie viele eindeutige Werte pro Feld?)
- Wie groß ist Ihr Rechner? Solr gerät in der Regel zuerst unter Speicherdruck.
- Wie hoch ist die QPS-Rate, die Sie erwarten? Spitzenwert? Durchschnitt?
- Wie viele Felder möchten Sie durchsuchen? Verwenden Sie edismax?
- Welche Arten von Filterabfragen werden Sie voraussichtlich ausführen?
- Und so weiter und so fort.
Leider ist es oft nicht möglich, diese im Voraus zu kennen, insbesondere wenn Solr in einer neuen Anwendung eingesetzt wird. Wenn Solr eine andere Anwendung ersetzt, können Sie sich bei der Abschätzung der Abfrageeigenschaften und der QPS auf einige reale Daten stützen, da Sie untersuchen können, wie Ihre aktuelle Suchmaschine genutzt wird. Aber auch hier gibt es Unwägbarkeiten. Ich garantiere Ihnen, dass sich die Art und Weise, wie Ihre Benutzer die Suchfunktionen nutzen, ändern wird, sobald Sie ihnen andere Möglichkeiten anbieten (was Sie mit Solr wahrscheinlich tun werden). Aber irgendwo müssen Sie ja anfangen.
Sie müssen einen Prototyp erstellen
Die einzige verlässliche Empfehlung, die wir unseren Kunden geben können, lautet: „Sie müssen mit Ihren Dokumenten und Ihren Abfragen einen Prototyp erstellen, um zu sehen, ob er funktioniert“. Wir empfehlen in der Regel, dass Sie zwei Zahlen von einer „typischen“ Hardware erhalten. Beachten Sie, dass wir uns in der Regel mehr Gedanken über die Abfrageleistung als über die Indizierungsleistung machen:
- Beginnen Sie mit, sagen wir, 20M Dokumenten auf Ihrem Rechner. Verwenden Sie etwas wie SolrMeter oder jMeter, um Abfragen an Ihre Hardware zu senden. Erhöhen Sie die Rate, mit der Abfragen an den Server gesendet werden, so lange, bis sich Ihre Antwortzeit verlängert. So erhalten Sie die theoretische maximale anhaltende QPS-Rate.
- Fügen Sie nun, sagen wir, 5 Mio. Dokumente hinzu und belasten Sie den Rechner mit, sagen wir, 80% der in Schritt 1 ermittelten QPS-Rate. Wenn Ihre QPS aufrechterhalten wird, fügen Sie weitere 5 Mio. Dokumente hinzu. Wiederholen Sie den Vorgang, bis Ihr Server zusammenbricht.
Da Sie nun eine maximale QPS-Rate und eine maximale Anzahl von Dokumenten für Ihre Zielhardware haben, können Sie verschiedene Überwachungssysteme einrichten, die Sie warnen, wenn Sie sich diesen Zahlen nähern, und die Kapazität entsprechend erweitern. Dies ist wichtig für die Mitarbeiter im operativen Bereich. Das sind die Leute, die am anderen Ende des Piepsers sitzen und nicht um 3:00 Uhr morgens angerufen werden wollen, um zu erfahren, dass ihr System gerade ausgefallen ist. Sie wissen es wirklich zu schätzen, wenn sie im Voraus gewarnt werden, dass sie sich ihrer Kapazität nähern.
Auf der Grundlage der obigen Angaben und der Beobachtung, wie verschiedene Kunden Solr nutzen, ist unsere erste Schätzung, dass ein „vernünftiger“ Rechner 40-50 Mio. Dokumente verarbeiten kann und Ihnen eine „vernünftige“ Antwortrate liefert. Aber Sie sehen bereits einen Teil des Problems. Definieren Sie „vernünftig“ in beiden Dimensionen. Alles, was wir Ihnen anbieten können, ist, dass Sie mit dem Aufbau einer Testumgebung mit einer größeren Anzahl von Dokumenten beginnen können. Wenn Sie einem Kunden sagen, dass er mit 20 Millionen Dokumenten beginnen soll (vorausgesetzt, es handelt sich nicht um Bände der Encyclopedia Britannica), können Sie zumindest die Erwartungen an den Umfang definieren.
Dennoch haben wir einige „Faustregeln“
Trotz aller Ausflüchte können wir sagen: „Beginnen Sie mit 20 Mio. Dokumenten für die Prototypisierung“. Wir sehen oft 40-50 Mio. Dokumente auf Produktionshardware.
Aber in der Truhe ist alles, was wir wissen, falsch
Wenn wir bei Lucid gefragt werden, warum die Leistung nicht so hoch ist, wie ein Kunde es gerne hätte, sehen wir uns als erstes an, wie viel Speicher von der Anwendung verwendet wird. Solr gerät in der Regel zuerst unter Druck, wenn der Speicherplatz knapp wird.
Der zweite Punkt, den wir uns ansehen, ist die Garbage Collection. In Mark Millers Beitrag finden Sie eine ausgezeichnete Einführung. Wir haben einige Situationen erlebt, in denen die JVM bei einem vollen GC-Zyklus nicht genug Speicher zurückgewinnen konnte, um die aktuelle Operation zu beenden, und dann viele Minuten lang wiederholt volle GC-Zyklen durchlaufen hat. Manchmal wurde dies auf einen JVM-Fehler zurückgeführt, manchmal auf ein Problem in Solr, manchmal darauf, dass einfach mehr Speicher benötigt wurde usw.
Also schauen wir reflexartig auf den Speicher, um herauszufinden, warum Solr langsam ist, und haben ein „Bauchgefühl“, wann und wie sich der Speicherdruck bemerkbar macht.
Aber in Solr/Lucene 4.0 (auch bekannt als „trunk“) gibt es einige sehr bedeutende Verbesserungen bei der Nutzung des Speichers. Wir müssen also einiges von dem, was wir „aus Erfahrung“ wissen, neu überprüfen.
Ich habe ein paar einfache Tests durchgeführt, um ein Gefühl für die Auswirkungen dieser Arbeit zu bekommen, und die Ergebnisse sind überraschend. Die Ergebnisse werden natürlich variieren. Die Schlussfolgerung daraus ist, dass die Kapazität auf 4.0 wahrscheinlich erneut getestet werden muss. Es würde mich überraschen, wenn die Leistung schlechter wäre, aber Ihre Schätzungen der Anzahl der Dokumente, die Ihre aktuelle Hardware bequem unterbringen kann, sind wahrscheinlich zu niedrig, wenn sie auf Tests vor dem Trunk beruhen.
Ich habe einen 11M-Dokumenten-Dump von Wikipedia genommen und ihn unter 3x und trunk mit Code von Ende März 2012 indiziert. Ich habe zwei sortierbare String-Felder erstellt, eines für Benutzer und eines für Titel, mit 233K bzw. 9,4M eindeutigen Werten. Dann habe ich den Server neu gestartet und mir den Speicherverbrauch nach einer Abfrage angesehen, die nach diesen beiden Feldern sortiert. Ich habe die jConsole und die VisualVM-Schaltfläche „GC now“ verwendet. Dann habe ich mir den Speicherverbrauch und die Objektanzahl angesehen.
Ergebnisse der Messung:
Hier sind die aktuellen Zahlen:
- Zeit für die erste Abfrage mit Sortierung (keine Aufwärmabfragen) 3x: 13 Sekunden, Stamm: 6 Sekunden.
- Speicherverbrauch 3x: 1.040M Stamm 366M. Ja, fast eine 2/3ige Reduzierung des Speicherverbrauchs. Und das ist die gesamte Programmgröße, ohne den Speicher zu zählen, der nur zum Starten von Solr und Jetty verwendet wird.
- Anzahl der Objekte auf dem Heap. 3x: 19.4M Stamm: 80K. Nein, das ist kein Tippfehler. Es befinden sich mehr als zwei Größenordnungen weniger Objekte auf dem Heap in trunk!
Diese Verringerung des Rohspeichers hat offensichtliche Auswirkungen auf die Kapazität, da Solr normalerweise aus Speichergründen unter Druck gerät. Sobald Sie den Speicher von Solr bis zu dem Punkt auslasten, an dem er anfängt zu swappen, müssen Sie den Index splitten, um die Leistung wiederherzustellen. Dieser Punkt ist jetzt wahrscheinlich ein ganzes Stück weiter weg. Ich bezweifle, dass Sie 3x so viele Dokumente auf einer bestimmten Hardware unterbringen können, aber das müssen Sie selbst testen.
Eine etwas subtilere Ersparnis ergibt sich bei der Garbage Collection. Egal, wie effizient Ihre Garbage Collection ist, das Sammeln von 19,5 Mio. Objekten ist auf jeden Fall langsamer als derselbe Vorgang bei 80.000 Objekten. Ich vermute, dass auch die Speicherfragmentierung verringert wird, aber das ist reine Spekulation.
OK, wie haben sie das gemacht?
Nun, es hat geholfen, dass die Programmierzwerge in einem Raum eingesperrt waren, in dem es weder Essen noch Bier gab. Eigentlich ist dies der Höhepunkt einer ganzen Reihe von Arbeiten einiger sehr, sehr talentierter Programmierer, die die Unzulänglichkeiten, die sie kannten, einfach nicht mehr ertragen konnten, als sie merkten, dass sie es besser machen konnten. Ich glaube, es ist schon etwas mehr als ein Jahr her.
Irgendwo lächeln die alten ‚C‘-Programmierer (ja, diese Bemerkung kommt mir bekannt vor). Die größte Einsparung an Speicher und Objekten ergibt sich aus der Zuweisung großer Puffer für die String-Daten, die wie ein großer Speicherblock behandelt werden, wobei der String-Offset und die Länge in Kontrollstrukturen gespeichert werden. Anstatt also zig kleine String-Objekte zu haben, gibt es nur eine kleine Anzahl wirklich großer Arrays von Bytes und einige Kontrollstrukturen, die auf sie verweisen.
Die einmalige Beschreibbarkeit eines Segments hilft hier. Bedenken Sie, wie umständlich dies wäre, wenn Sie zulassen würden, dass sich die Zeichenketten ändern. Dieses schöne, dicht gepackte Array von Bytes wäre allen Unwägbarkeiten von sich ändernden Daten ausgesetzt. Das Problem war schon schwierig genug, ohne den Heap-Manager neu zu erfinden! Da sich einmal geschriebene Segmente nicht mehr ändern, können diese Strukturen erstellt werden, wenn ein Sucher geöffnet wird, ohne dass Sie sich mit den Problemen befassen müssen, die veränderliche Daten mit sich bringen würden. Und sie können auf einmal weggeworfen werden, wenn der Sucher geschlossen wird. Diese beiden Eigenschaften von Solr-Segmenten machen diese Strategie viel praktikabler, als sie es sonst sein könnte. Oh, und das ist ein weiterer Grund dafür, dass die Aktualisierung einzelner Felder in einem Solr-Dokument „etwas ist, worüber wir nachdenken werden“…
Beachten Sie, dass bei diesem Test beide Felder, nach denen ich sortiere, Strings sind. Ich habe mich absichtlich für String-Typen entschieden, weil ich mir ziemlich sicher war, dass sich die Verbesserungen bei der Speichernutzung deutlich zeigen würden. Ich war nur nicht ganz darauf vorbereitet, wie deutlich.
Ich vereinfache hier, und ich hatte nichts mit dem Schreiben des Codes zu tun, es ist also ein Überblick. Aber die Ergebnisse sprechen für sich selbst. Zusammen mit der Tatsache, dass Java String-Objekte etwa 40 Byte Overhead haben, bevor sie das erste Byte tatsächlicher Daten speichern, und… nun ja…