Skalierbare Datenhaltung mit der Lambda-Architektur

Motivation

Die nicht nur wachsenden Mengen sondern auch wachsende Frequenz an Daten, die durch moderne Webanwendungen, Sensoren mobiler Endgeräte, und unzähliger weiterer Datenquellen generiert werden, lassen relationale Datenbanken mit klassischer Datenhaltung schnell an ihre Grenzen stoßen. Während eines Updates werden Tabellenzeilen gesperrt, was zu Problemen mit Performance und Verfügbarkeit der Anwendung führt. Verteilt man die Datenbank auf ein Cluster (durch z.B. Sharding1), lassen sich die Schwierigkeiten vorübergehend lösen, doch wird ein solcher Cluster nur mit großem Aufwand und hoher Fehleranfälligkeit betrieben. Das Puffern der Daten um sie dann in Batches in eine Datenbank zu schreiben hilft auch nur kurzfristig bevor die Datenbank wieder zum Flaschenhals wird oder andere Probleme auftauchen.

NoSQL-Datenbanken wie MongoDB sind von Grund auf für Sharding und Replizierung entwickelt worden. Doch auch ein MongoDB-Cluster erlaubt maximal zwölf Replicas und bringt eine eigene Kategorie von Problemen mit sich wenn z.B. der Primärknoten abstürzt und die Replicas eine hohe zeitliche Differenz aufweisen. Der Mangel an Transaktionen und Joins verschiebt das Problem des Mehrbenutzerzugriffs von der Datenbankebene auf die Applikationsebene.

Es ist also nötig, das Grundverständnis von Daten neu zu überdenken.

Die Lambda-Architektur

Fakten und Informationen

Die Lambda-Architektur ist eine von Nathan Marz2 entworfene Architektur, die die klassische Datenhaltung hinterfragt und auf Basis aktueller BigData-Technologien neu entwirft.

Der Name leitet sich (vermutlich) vom Lambda-Kalkül als Grundlage der funktionalen Programmierung her. Ein wesentliches Merkmal der funktionalen Programmierung ist das Konzept von unverändlichen Daten (immutable data), d.h. dass Veränderungen an Daten nur Kopien dieser Daten erzeugen und die ursprünglichen Daten niemals verändert werden.

In der Lambda-Architektur werden vorhandene Daten niemals aktualisiert. Jede Veränderung wird als eigenständiges Faktum angesehen, das zu einem bestimmten Zeitpunkt als wahr gilt. Eine Veränderung der Daten bedeutet also, dass nur ein neues Faktum für einen aktuelleren Zeitpunkt hinzukommt (append-only).

Würde man also einen Kommentar zu einem Blogpost ändern, so hätten wir zwei Fakten: den gesamten Kommentar zum Zeitpunkt x0, und den gesamten Kommentar zum Zeitpunkt x1.

Das zweite grundlegende Prinzip der Lambda-Architektur ist die Definition von Information als eine Funktion der Fakten.

Information = Funktion(Fakten)

Informationen leiten sich also aus den Berechnungen der einzelnen Fakten her. Beispielsweise wäre die Anzahl der Kommentare zu einem Blogpost eine Funktion, die die einzelnen Kommentare zählt. Die Anzahl wäre kein Faktum, sondern nur eine berechnete Information.

Diese Art und Weise über Daten nachzudenken erhöht den Wert der Daten, da man nicht nur über den letzten Wert verfügt, sondern über alle Werte. Für einen Online-Händler ist es beispielsweise nicht nur relevant, welche Artikel der Kunde beim Bestellvorgang im Warenkorb hat, sondern auch welche er in der Zwischenzeit hineingelegt und wieder herausgenommen hat.

(Menschliche) Fehlertoleranz

Durch die Trennung in Fakten und Informationen reduzieren wir auch die Anfälligkeit für Programmierfehler. Enthält eine Berechnung einen Fehler, wird das berechnete Ergebnis einfach verworfen und aufgrund der Fakten neu ermittelt. Ein Algorithmus kann damit unsere Daten nicht korrumpieren.

Die Fakten selbst werden in ebenfalls fehlertoleranten Systemen gespeichert.

Ebenen

Die Lambda-Architektur beschreibt ein BigData-System, das sich in drei Ebenen aufteilt - den Batch Layer, den Serving Layer, und den Speed Layer.

Lambda-Architektur Ebenen

Batch Layer

Der Batch Layer enthält sämtliche Fakten in redundanter (und damit fehlertoleranter) Ausführung. Im Batch Layer werden auf den Fakten die Berechnungen ausgeführt. Aufgrund der schieren Menge an Fakten ist mit einer hohen Latenz zu rechnen. Je nach Anforderung können Berechnungen durchaus Stunden brauchen. Neu eintreffende Fakten werden zu den vorhandenen Fakten hinzugefügt und beim nächsten Durchlauf der Berechnungen berücksichtigt.

Serving Layer

Um die hohe Latenz des Batch Layers abzufangen, werden die Ergebnisse der Berechnungen im Serving Layer gespeichert. Der Serving Layer dient externen Systemen dazu, die gewünschten Informationen abzufragen. Ist eine Berechnung fertig, werden alle Daten im Serving Layer ersetzt. Dadurch entfallen komplexe Updatemechanismen und es wird geradzu trivial, den Zugriff auf die Informationen zu skalieren.

Speed Layer

Die hohe Latenz des Batch Layers wirkt sich letztlich auch auf den Serving Layer aus, so dass man davon ausgehen muss, dass der Serving Layer niemals den aktuellen Stand der Informationen enthält. Diese Lücke wird vom Speed Layer geschlossen, der ebenfalls alle neuen Daten erhält und darauf direkt die gewünschten Berechnungen ausführt und sie temporär speichert. Wenn der Batch Layer aufholt, wird der im Serving Layer verfügbare Teil der Informationen im Speed Layer wieder gelöscht.

Der Speed Layer ist die einzig komplexe Komponente der Lambda-Architektur, da er sich damit beschäftigen muss, wie neu eintreffende Ergebnisse mit den bereits errechneten Informationen kombiniert werden. Dazu gibt es eine Reihe von Strategien, die den Rahmen dieses Artikels übersteigen würden3.

Ein externes System wird dann die Ergebnisse aus Serving Layer und Speed Layer kombinieren um eine aktuelle Sicht auf die Daten zu gewähren.

Beispiel-Implementierung der Lambda-Architektur

Für den Batch Layer bietet sich üblicherweise Hadoop an - in HDFS können die Fakten fehlertolerant hinterlegt werden, und per MapReduce können skalierbar Berechnungen ausgeführt werden. Neue Daten werden in eine Message Queue wie Kafka gelegt und in festen Intervallen über ein ETL-Tool wie Camus in HDFS geschrieben.

Die Ergebnisse der Berechnungen können dann in einer Read-Only-Datenbank wie SploutSQL abgelegt werden, die den Serving Layer abbildet. In Splout werden Tabellen und deren Inhalte direkt aus HDFS generiert. Splout bietet zudem ein Java- und ein REST-API zum direkten Zugriff auf die Daten an.

Den Speed-Layer kann mit einem Stream-Framework wie Storm umsetzen. Neue Daten werden in eine so genannte Topologie eingespeist, weiter verarbeitet und dann in Datenbanken wie Cassandra oder HBase solange gespeichert, bis der Batch Layer aufgeholt hat.

Jedes dieser Tools stellt dabei nur ein (erprobtes) Beispiel dar und kann durch jedes andere Tool oder Framework, das die gleiche Aufgabe erledigt, ersetzt werden. Eine Alternative zu Hadoop ist Spark, Splout kann man auch durch ElephantDB ersetzen, Storm durch Samza, S4 oder Akka, und so weiter.

Fazit

Die Lambda-Architektur bietet einen erfrischenden Ansatz, Daten zu organisieren und auszuwerten. Dabei wird die Performance durch individuell skalierbare Komponenten vereinfacht, und die Fehlertoleranz durch dafür konzipierte Systeme erhöht.

Doch es gibt auch Kritik an der Lambda-Architektur, denn sämtliche Berechnungen müssen immer doppelt implementiert werden - ein mal für Batch, und noch mal für Realtime. Aus dieser Kritik ist die Kappa-Architektur entstanden.

  1. http://de.wikipedia.org/wiki/Sharding#Fragmentierung

  2. Nathan Marz ist ehemaliger Softwareentwickler bei Twitter, der unter anderem mehrere Startups gegründet und diverse BigData-Lösungen entwickelt hat. Die Lambda-Architektur wird ursprünglich in folgendem Artikel dargelegt: http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html

  3. Beispielsweise Conflict-free Replicated Data Types (CRTDs), Monoide, und mehr.

Diesen Post teilen

RSS-Feed

Neue Posts direkt im Newsreader.

RSS-Feed abonnieren

Newsletter

Neue Posts sowie Neuigkeiten rund um Big Data, Spark, und Scala. Maximal eine E-Mail im Monat.

Kommentare