Seitenanfang

Delphin, Elch und Blatt: Das Rennen

mySQL, ElasticSearch und MongoDB sind installiert und mit Testdaten befüllt - Zeit für den Geschwindigkeitsvergleich. Zur Erinnerung: Es geht um die Performance bei der parallelen Ausführung unterschiedlicher komplexer Suchanfragen einer existierenden Applikation, die mySQL regelmäßig an seine Grenzen bringt. ElasticSearch hat seinen Ruf als hochperformante Suchmaschine zu verteidigen und MongoDB soll zeigen, wie eine andere Datenbank im Vergleich abschneidet.

ElasticSearch-MongoDB-MySQL_finish.jpgFür den eigentlichen Benchmark habe ich 8 Abfragen zusammengestellt. Alle entsprechen oder basieren auf tatsächlichen Abfragen der Live-Datenbank wie sie täglich von Benutzern der Applikation ausgeführt werden.

Die erste Überraschung boten die Ergebnisse: Bei einigen Abfragen lieferte mySQL z.T. wesentlich weniger Ergebnisse als die Konkurrenten. Als Ursache stellte sich eine Schwäche in den generierten SQL-Statements heraus, die bei den MongoDB- und ElasticSearch-Abfragen systembedingt nicht auftreten konnte: JOIN anstatt LEFT JOIN. Die beiden NoSQL-Lösungen brauchen keine normalisierten/verknüpften Tabellen, sondern finden alle notwendigen Daten in einem Dokument.

Perfekte Welt

Der erste Vergleich lief in einer perfekten Welt ab: Ein Datenbankserver nur für das Testscript, keine anderen Nutzer und genügend Speicher, um alle Daten- und Indexdateien im RAM oder zumindest Betriebssystem-Cache zu halten. Jedes Query wurde einzeln abgefeuert und alle Ergebnisse wurden abgeholt und dann vom Script verworfen.

Insbesondere letzteres wirft Elasticsearch zurück, dass normalerweise nur 10 Ergebnisse tatsächlich ausliefert und den Rest einfach zählt. Ohne die Vorgabe, alle Ergebnisse zu liefern, ist die Suchmaschine unangefochten auf Platz 1, mit Rückgabe aller Ergebnisse sieht das Rennen jedoch knapper aus.

Nach 7 von 8 Abfragen (mit 152.000, 1500, 2400, 7, 143, 1 und 150 Ergebnissen) zeigt sich folgender Zwischenstand:

  1. ElasticSearch: 5.401 Sekunden
  2. mySQL: 6.194 Sekunden
  3. MongoDB: 52.544 Sekunden

MongoDB überrascht mich wirklich. Kaum zu glauben, dass die moderne NoSQL-Datenbank so schwach abschneidet. Die Indices der MongoDB-Collection sind analog zu den mySQL-Indices gesetzt und ich sehe kein großes Verbesserungspotential. Ich bin gespannt, ob sich das Bild bei realistischeren Tests (mit parallelen Abfragen) ändert.

Die Ergebnisse sind übrigens reproduzierbar. Natürlich weichen die exakten Zahlen in jedem Lauf etwas ab, aber die Reihenfolge bleibt immer gleich und auch die Abstände unterliegen keinen großen Schwankungen.

Die 8. Abfrage lieferte 227.000 Ergebnisse und führt zu einer Änderung der Rangfolge:

  1. mySQL: 10,017 Sekunden
  2. ElasticSearch: 13,469 Sekunden
  3. MongoDB: 68,224 Sekunden

ElasticSearch sucht anscheinend schneller, lässt sich aber mit der Rückgabe der Ergebnisse mehr Zeit - zumindest bei Einzelabfragen.

Harte Realität

In der Realität wird ein Datenbankserver allerdings von mehreren Anfragen gleichzeitig benutzt. Um dieses Szenario zu simulieren, werden alle 8 Abfragen zeitgleich über einzelne Verbindungen an den Server geschickt. Gemessen wird die Gesamtzeit zur Beantwortung aller Einzelabfragen (Summe der Zeiten) und die tatsächlich verstrichene Zeit.

Bei 8 parallelen Abfragen:

  1. mySQL: 13,674 Sekunden Gesamtzeit / 4,769 Sekunden tatsächliche Zeit
  2. ElasticSearch: 19,921 Sekunden Gesamtzeit / 9,883 Sekunden tatsächliche Zeit
  3. MongoDB: 71,968 Sekunden Gesamtzeit / 19,631 Sekunden tatsächliche Zeit

Bei je zwei gleichzeitigen Aufrufen jeder Abfrage (16 insgesamt):

  1. mySQL: 30,644 Sekunden Gesamtzeit / 6,792 Sekunden tatsächliche Zeit
  2. ElasticSearch: 58,327 Sekunden Gesamtzeit / 17,392 Sekunden tatsächliche Zeit
  3. MongoDB: 213,142 Sekunden Gesamtzeit / 27,060 Sekunden tatsächliche Zeit

Interessant ist dabei, dass die Performance von ElasticSearch sehr stark von der Ergebnismenge abhängig zu sein scheint: Die beiden Abfragen mit 152.000 und 227.000 Ergebnissen brauchen jeweils 12 bzw. 14 Sekunden (je Zugriff), die anderen liegen alle unter einer Sekunde. Bei mySQL ist kein entscheidender Faktor für die benötigte Zeit erkennbar und bei MongoDB scheint die Komplexität der Suchanfrage ausschlaggebend zu sein.

Wird jede Abfrage 5fach ausgeführt (40 parallele Anfragen insgesamt), gibt ElasticSearch auf: "No nodes are available" oder "Timed out while waiting for socket to become ready for reading, called from sub Search::Elasticsearch::Transport::try" deuten darauf hin, dass der Server mit zu vielen parallelen Anfragen schlichtweg überfordert ist. Auch das Starten zusätzlicher Nodes (auf dem gleichen Server) brachte keine Besserung.

Gleichzeitige Abfragen

Bei mySQL ist noch zu bedenken, dass die Abfragen in einem echten MyISAM-Cluster nicht parallel ausgeführt werden würden. Die beteiligten Tabellen werden üblicherweise mehrfach pro Sekunde geschrieben und normalerweise blockiert eine Schreiboperation auf eine Tabelle die gerade gelesen wird alle weiteren Leseoperationen - so zumindest meine Erfahrungen aus der Praxis. Ich tendiere deswegen dazu, bei mySQL die "30,644 Sekunden" als tatsächlichen Wert anzunehmen. Selbst dieser Wert ist noch sehr optimistisch - im Livesystem liegt der Durchschnitt bei rund 82 Sekunden, die längste Abfrage brauchte respektable 10265 Sekunden (knapp 3 Stunden)! Platz 10 der längsten Abfragen brauchte immernoch rund 1,5 Stunden und war wesentlich einfacher als meine Testabfragen.

ElasticSearch pflegt neue Dokumente bzw. Änderungen einmal pro Sekunde in den Index ein. Da 6 von 8 Abfragen in weniger als einer Sekunde bearbeitet wurden, würde ich nicht mit Locking-Problemen rechnen, bei den beiden längeren Abfragen kann ich keine begründete Vermutung anstellen.

MongoDB steht sehr schlecht da und ich habe gerade keine Idee, wie sich das Problem lösen läst. Bei der Locking-Frage ist die beliebte NoSQL-Datenbank allerdings außen vor: Im gleichen Projekt, aus auch dem mein Testszenario stammt, verrichtet eine MongoDB ihren Dienst und wird quasi permanent von etwa 60 Clients mit Daten befüllt ohne dass sich Auswirkungen auf die Leseperformance zeigen.

 

Noch keine Kommentare. Schreib was dazu

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>