Mittwoch, 1. Oktober 2014

Ingestion rates


Im September gab es eine (durchaus interessante) Veranstaltung in Stuttgart, die mongoDB IoT european city tour. Thema war, ob (na ja, also natürlich "das") mongodb die ideale Basis für das Internet of Things sei. Dabei ergab sich die Gelegenheit, einen der Chief sonstwas Architects von mongodb zu fragen, warum (zum Geier) man denn eine (dokumentenorientierte) NoSQL-Datenbank braucht, um sehr einfach strukturierte Sensordaten zu speichern. Nach meiner unmassgeblichen Ansicht ist eine relationale Datenbank hier viel besser geeignet.

Die Antwort war: "Ingestion rate" (nach einigem Nachdenken kam dann noch "If you want to annotate your data ...", das ist ein guter Punkt, aber halt nur, wenn man das dann auch in unstrukturierter Form machen will. Und nach noch längerem Nachdenken "Open Source").

Also "Ingestion rate". Das Lieblingswort der NoSQL-Anbieter, wie mir scheint. Solche Aussagen wecken immer ganz schnell meine Neugier. Also habe ich die Zeit vor Semesterstart für einen kleinen Benchmark genutzt.

Das Szenario ist einfach: Eine Anzahl von Sensoren, die Daten liefern, beispielsweise 100 Sensoren, die ein paar Mal pro Sekunde einen Wert (etwa einen Ort oder eine Geschwindigkeit) liefern. Gespeichert wird für jede Messung die Zeit, der Wert, die Art des Werts und die ID des Sensors. Alles ints. Transaktionen brauchen wir hier eigentlich keine, da keine Werte geändert werden. Die einzigen Operationen sind das Anlegen neuer Datensätze und Lesen bereits bestehender.

Zunächst in einer mysql-Datenbank. Ein INSERT pro Wert, MyISAM-Engine. Kein Index. Dann mongoDB. Zunächst auch ein Wert pro insert, dann bulk-insert mit jeweils 1000 Werten. Auch ohne Index. In der Realität werden hier also die Zahlen schlechter (also langsamer) werden, denn ohne Index dauert es viel zu lang, die Daten zu finden.

Wenn man sich mal genauer überlegt, was man in diesem Fall eigentlich braucht, dann kommt man (hoffentlich) früher oder später darauf, dass eine Datenbank eigentlich overkill ist: Eine Zeitreihe kann man leicht in einer (Binär-) Datei speichern. Das Einfügen (also hier ja nur ein Anhängen) geht einfach. Suchen ist etwas schwieriger. Die typischen Abfragen in einem solchen System sind "Gib mir die Werte aus einem bestimmten Zeitintervall", beispielsweise den letzten zehn Sekunden usw.

Wenn hier jeweils die ganze Datei durchsucht werden muss, dann ist das viel zu langsam. Also braucht man einen Index. Da man in der Regel aber sowieso aggregierte Werte haben will, um die Darstellung auf unterschiedlichen Zeitskalen zu beschleunigen, ist das gar nicht so schwierig: Man speichert sowieso nicht nur die Originaldaten, sondern dazu noch Mittelwerte (und ggf. andere Verteilungsparameter) je Sekunde, Minute, Stunde, Tag usw. Wenn man hier jeweils noch die (ungefähre) Position dieses Intervalls in der grossen Datei mit den Originaldaten speichert, hat man eine Art B*-Baum für Zeitreihendaten. Der oberste Knoten sind die Monate(oder Jahre oder wasauchimmer). Auf der nächsten Ebene kommen die Tage, dann die Stunden, dann die Minuten, dann die Sekunden, dann die Daten. Sucht man die Daten für einen bestimmten Zeitpunkt, fängt man oben an, kommt so zum richtigen Tag, dann zur richtigen Stunde, zur Minute, zur Sekunde und schliesslich in die Datei, wo man einen Block oder so liest und die Daten hat. Programmieraufwand so in der Größenordnung von ein paar Tagen.

Das Ergebnis ist beeindruckend: MySQL und mongoDB liegen eher nah beieinander, MySQL etwa doppelt so schnell wie mongoDB. Beide in der Größenordnung (genauer ist das eh nicht, wir wollen ja nur ungefähre Zahlen haben) von 10.000 Datensätzen pro Sekunde.

Die "handgestrickte" Version mit Dateien (hier wurde nur der Index für die Sekunden realisiert, die oberen Ebenen wurden, da für die Performance irrelevant, weggelassen) schafft etwa 2 Millionen Datensätze pro Sekunde, also etwa 200 mal mehr als die Datenbanken !

Interessant ist hier, dass der bulk insert bei mongoDB praktisch keine Verbesserung bringt (bulk inserts scheinen ein schwieriges Thema zu sein, siehe etwa hier und hier).

Wenn man bei den Datenbanken noch Indices verwendet, muss man sehr ausfpassen, dass die Performance nicht in den Keller geht (siehe etwa hier).



Also: Wegen "Ingestion rate" braucht man keine NoSQL-Datenbank !



Üblicherweise kommt dann der Einwand, dass man NoSQL-Datenbanken leichter verteilen kann und so eine bessere Performance erzielen kann. Einen interesasanten Benchmark mit verteilten MySQL-Datenbanken, bei dem 15 Instanzen etwa 1 Million Datensätze pro Sekunde schaffen, gibt's hier.
Die schaffen etwa 150.000 pro Sekunde, was ganz gut zu meinen Messungen passt: Ich habe mein 4 Jahre altes Macbook verwendet, die hatten eine dicke Amazon Instanz. Passt.

Braucht man mehr Performance muss man in jedem Fall verteilen. Das ist dann aber schon ganz schön viel: Nehmen wir mal an, dass ein vernünftiger Rechner mit SSDs den zehnfachen Durchsatz wie mein altes Macbook schafft (das ist eher konservativ), dann wären das immerhin 20 Millionen Datensätze pro Sekunde .... die muss man erstmal haben.

Falls jeder Sensor pro Sekunde einen Datensatz liefert (das sind so übliche Szenarien, etwa auch bei der IoT-Veranstaltung die intelligenten Akkuschrauber von Bosch), dann sind das 20 Millionen Sensoren .....

Aber in der Tat, es gibt Anwendungsfälle, wo man so viele hat (etwa bei TelCos). Dann sind verteilte Dateisysteme notwendig, ein schönes Beispiel mit 100 Millionen Datensätzen pro Sekunde gibt's hier.

Also nochmal: Wegen Ingestion rates braucht man keine NoSQL-Datenbank ! Zumindest in einem IoT-Szenario, bei komplexen Dokumenten mag das wohl sein. Haben wir hier aber nicht ! Nein !

Bleibt also noch das Argument mit der Annotation. Bei Sensordaten kann man hier zwei Grenzfälle sehen: Bei Massendate die Annotation mit Events. Das also aus anderen Quellen stammende oder durch Auswertungen erzeugte Informationen über besondere Ereignisse (etwa die Überschreitung von Grenzwerten oder die Clusterung von Daten) hinzugefügt werden. Das geht mit relationalen Datenbanken natürlich hervorragend. Einfach eine zusätzliche Tabelle angelegt, die per Fremdschlüssel auf die entsprechenden Datensätze verweist.

Der andere Grenzfall wären meistens manuell erstellte, in jedem Fall aber unstrukturierte Daten in unvorhersehbarer Form. Die kann man tatsächlich gut in NoSQL-Datenbanken speichern. Die Frage ist, was bringt das ? Unstrukturierte Daten auszuwerten ist, insbesondere wenn man überhaupt nicht weiss, worum es sich handelt, gar nicht so einfach. Da bleibt eigentlich nur eine Volltextsuche, semantische Textanalyse usw. Das kann man aber auch mit einer relationalen Datenbank gut machen, wenn man diese Annotationen als BLOB speichert.

Bleibt "Open Source". Ist MySQL auch. Zumindest die Community Edition. Wie bei mongoDB auch.

Was bleibt also von den Argumenten übrig ?

Nix.

Den Quellcode der verwendeten Programme gibt's hier.