Einsatz der Cassandra-Datenbank

Cassandra im Einsatz

Cassandra im Einsatz

Die grundlegenden Bestandteile des Cassandra-Datenmodells sind der Keyspace, Keys, Columns, Column Family sowie Super Columns. Für den Einsatz definiert man, über einen sogenannten Keyspace, einen Bereich mit zusammenhängenden Daten. Es bietet sich an, alle Daten eines Projektes in einem gemeinsamen Keyspace abzulegen. Jeder Eintrag innerhalb einer Cassandra-Datenbank lässt sich über einen Key identifizieren. Die eigentliche Datenablage erfolgt – wie der Name Spaltendatenbank bereits vermuten lässt – in Columns, die jeweils ein Paar "Schlüssel-Wert" enthalten. Mehrere Columns können zu einer Super Column zusammengefasst werden, auf die später bei Leseoperationen einen effizienteren Zugriff erlaubt.

Ein Beispiel: Sind innerhalb einer Adressensammlung mehrere Telefonnummern angegeben, so legt man zunächst jede Nummer mit einem passenden Namen innerhalb einer Column ab, beispielsweise in den beiden Columns Mobil: 0171-23456789 und Festnetz: 089-4711. Über diese Columns definiert man nun eine Super Column mit dem Namen Telefonnummern, auf die sich mit einer Abfrage über alle enthaltenen Informationen zugreifen lässt (in relationalen Systemen wäre für einen Zugriff auf eine solche 1:n-Beziehung eine Join-Abfrage notwendig). Eine Column Family schließlich fasst Columns oder Super Columns zusammen. Auf die Daten innerhalb dieser Column Family kann mittels der Keys zugegriffen werden.

Neue Daten landen beim Eintrag in Cassandra zunächst im Hauptspeicher und verteilen sich von dort später auf die zugehörigen Knoten im Cassandra-Cluster. Als Folge dieses schnellen Hauptspeicher-Eintrages und der Tatsache, dass bei Lesezugriffen auf den Hauptspeicher und die Platten zugegriffen werden muss (da das System ja nicht davon ausgehen kann, dass alle Schreiboperationen aus dem Hauptspeicher auf die Festplatten bereits abgeschlossen sind), ergibt sich die Situation, dass Schreiboperationen in Cassandra-Systemen meist wesentlich schneller als Leseoperationen vonstatten gehen. Interessante Zahlen zu diesen Performance-Unterschieden zwischen Schreib- und Leseoperationen, sowie ein Vergleich der Zugriffszeiten bei einem MySQL- und einem Cassandra-System findet man in einer Präsentation der Cassandra-Entwickler Lakshman und Malik: In einem großen System (mehr als 50 Gigabyte Daten) ergab sich durch den Wechsel von MySQL zu Cassandra eine Verbesserung des Schreibzugriffs von 300 Millisekunden auf 0,12 Millisekunden und beim Lesezugriff von 350 Millisekunden auf 15 Millisekunden.

Von Thrift über Hector zu CQL

Neben den genannten Performance- und Skalierbarkeits-Argumenten stellen auch Client-APIs ein wichtiges Kriterium für die Auswahl einer Datenbank dar. Die Frage ist ja, wie man in Anwendungsprogrammen auf die Daten innerhalb eines Cassandra-Systems zugreifen kann. Geht man vom System selber aus, so gibt es zunächst nur die Möglichkeit, über das Thrift-Framework auf die Daten zuzugreifen. Da von einem direkten Einsatz von Thrift aber beinahe in jedem Cassandra-Tutorial abgeraten wird, soll die Variante hier nicht näher vorgestellt werden – zumal Thrift von den Cassandra-Entwicklern auch nur denjenigen empfohlen wird, die eine Client-Library für eine spezielle Programmiersprache erstellen wollen. Für verschiedene Sprachen gibt es allerdings schon verfügbare Bibliotheken, einen Überblick gibt es im Apache-Wiki. Speziell in Java-Projekten nutzt man häufig Hector als Client-Bibliothek.

Wo bei relationalen Systemen SQL für den Zugriff auf die Daten Anwendung findet, kommt für NoSQL-Datenbanken Map/Reduce ins Spiel. Map/Reduce ist ein Verfahren zur effizienten Verarbeitung von Abfragen auf große Datenmengen. Es beruht auf Prinzipien der funktionalen Programmierung und hat seinen Namen durch deren Methoden map und reduce erhalten. Die verteilte Verarbeitung einer Query erfolgt hier in zwei Schritten. Im ersten Schritt werden über eine Map-Funktion lokal Zwischenergebnisse berechnet und abgelegt, die im zweiten Schritt über eine Reduce-Funktion zum Gesamtergebnis zusammengefasst werden. Die Implementierung solcher Map-Reduce-Funktionen erfordert allerdings einige Vorkenntnisse, was zusammen mit dem Test der Funktionen zeitaufwändig sein kann. Das ist ein in letzter Zeit immer wieder genannter Kritikpunkt und damit ein Hindernis für die weitere Ausbreitung von NoSQL-Datenbanken.

Mit der im Juni 2011 erschienenen Version 0.8 haben die Cassandra-Entwickler nun auf diese Kritik reagiert und mit der eigenen Abfragesprache CQL (Cassandra Query Language) eine Art "SQL für Cassandra", inklusive zugehörigem JDBC-Treiber, bereitgestellt, deren Syntax stark an SQL angelehnt ist:

USE <KEYSPACE>;
SELECT <COLUMN> FROM <COLUMN FAMILY> WHERE <KEY> = keyname;
UPDATE <COLUMN FAMILY> SET <COLUMN> = value WHERE <KEY> = keyname;

Fazit

Mit Cassandra steht innerhalb der NoSQL-Familie eine weitere Datenbank für den Einsatz in Projekten mit sehr großen Datenmengen zur Verfügung. Als Stärken von Cassandra sind vor allem die größtenteils automatisch verwaltete horizontale Skalierung sowie die schnellen Lese- und Schreibzugriffe zu nennen – falls der Zugriff exakt zur Speicherung der Daten passt, das System also von Anfang an auf eine bestimmte Einsatzsituation hin entworfen wurde. Ad-Hoc-Abfragen dagegen sind, wie bei vielen NoSQL-Systemen, nicht die Stärke von Cassandra. Mit der Abfragesprache CQL in der neuesten Version 0.8 versuchen die Cassandra-Entwickler jedoch, der verstärkt zu hörenden Kritik an den zu komplexen Abfragemöglichkeiten entgegenzuwirken.

Das Cassandra sich als Datenbank in großen Systemen eignet, beweist ihr Einsatz bei Facebook sowie die Tatsache, dass die Facebook-Entwickler Cassandra exakt für Anforderungen in solchen Großsystemen entworfen haben (auch, wenn Facebook inzwischen auf eine andere Spaltendatenbank (HBase) umgestiegen ist).

Rudolf Jansen
arbeitet als freiberuflicher Software-Entwickler und Journalist in Aachen. Seine Tätigkeitsschwerpunkte liegen in den Bereichen Java, C++, XML und Datenbanken.