Cassandra

Das Datenbanksystem Cassandra gehört zu den spaltenorientierten Datenbanken und begann als internes Projekt der Software-Ingenieure von Facebook, um die Suche im Posteingang zu optimieren. Später, wurde der Quellcode unter der GNU General Public License freigegeben und ist heute ein Top-Level-Projekt der Apache Software Foundation.

Datenmodell

Das Datenmodell von Cassandra ist in der Art entworfen um die Verteilung der Daten in großen Cluster zu unterstützen. Es gibt einige Ähnlichkeiten mit dem Datenmodell der relationalen Datenbanken, wie z.B., dass die Column Families Tabellen entsprechen und die Keyspaces Datenbanken. Aber es gibt erhebliche Unterschiede zwischen den beiden Modellen. Cassandra unterstützt die Erstellung und Entfernung von Spalten ohne die Notwendigkeit die Struktur einer Column Family zu verändern.

Das Datenmodell von Cassandra hat keine logische Struktur und kein Schema. Eine effiziente Modellierungsvorgehensweise ist eine Column Family für jede erwartete Anfrage zu erstellen. Auf diese Weise werden die Daten zwar denormalisiert (Siehe: Normalisieren, aber sie sind in derart strukturiert, so dass jede Column Family auf eine bestimmte Art von Anfrage beantwortet.

Das Motto, dass von dieser Modellierungsart rausfolgen kann, ist: „First write your queries, then model your data“ bzw. „Erst formuliere die Queries, und danach modelliere die Daten.“

Column
Die Spalte (Column) ist das kleinste Teil des Modells und besteht aus den Namen der Spalte, Daten und einem Zeitstempel (die Zeit, in welcher die Daten in jeder Spalte importiert wurden). In JSON-Form kann man diese wie folgend ausdrücken:


Columns und Super Column
 {
	name: 	 "username",
	value:	 "foobar",
	timestamp: "13377331"
 }

Ohne den Zeitstempel sind diese Colums analog zu den key/values Paaren wie sie bei Key Value-Datenbanksystemen zu finden sind.

Super Column
Eine Super Column besteht aus einem Tupel name/value, wobei der Name, dem Namen des Super Columns entspricht, und die Value aus einer Liste von Spalten besteht, die je als Primärschlüssel den Namen der einzelnen Spalten enthält. Dies wird in JSON-Form wie folgt ausgedrückt:

 {
	name: "address",
	value: {
		street: {name: "street", value: "Foobarstr. 1", timestamp: 333222332},
		city: {name: "city", value: "Foocity", timestamp: 342423432},
		zipcode: { name: "zipcode", value: "12345", timestamp: 9859689}
	}
 }

Der Unterschied zwischen Columns und Super Columns ist, dass bei den Columns die Daten (Values) vom Typ String sind und die Daten einer Spalte entsprechen, wobei in den Super Columns die Values einer Liste von Spalten entsprechen. Wie in der Abbildung "Columns und Super Column" gezeigt ist, haben die Super Columns keinen Zeitstempel.


Beispiel einer Column Family

Column Family
Die Column Families entsprechen Tabellen in den relationalen Datenbanken. Sie gruppieren Spalten mit dem gleichen oder ähnlichen Inhalt zusammen. Jede Zeile ist eindeutig identifizierbar mit einem Schlüssel. Sie kann mehrere Spalten haben und im Gegensatz zu den Tabellen im relationalen Datenbanken Systemen, muss sie nicht die gleiche Struktur haben wie die andere Zeilen, die der gleichen Familie angehören. Im Wesentlichen hat eine Column Family gar kein Schema. Im nächsten Beispiel es ist zu sehen, dass die erste Zeile eine völlig verschiedene Struktur als die zweite hat.

 profile = {
	foo: {
		username:	"foo",
		email:		"foo@bar.com",
		gender:		"female"
	},
	bar: {
		username:	"bar",
		email:		"bar@foo.com",
		birthday:	"1970",
		website:	"foobar.com"
	}
 }

Super Column Family
Der zweite Gruppierungsart der Spalten sind die Super Column Families, die Super Columns zusammen gruppieren. In diesem Fall enthält jede Zeile eine Reihe von Super Columns, welche ebenfalls eindeutig mit einem Schlüssel (row-key) identifizierbar ist.

 AddressBook = {
	foo: {
		Nick: {street: "Blahstr. 23", zip: "12345", city: "Munchen"},
		Sam: {street: "Zongstr. 8", zip: "65421", city: "Nuxz"},
		Alice: {street: "Bingstr. 997a", zip: "87221", city: "Hoax"}
	}, 
	bar: {
		Chandler: {street: "Garrisonstr. 23", zip: "78412", city: "Cologne"},
		Kermit: {street: "Sesamstr. 1", zip: "25492", city: "Hunx"},
		Alice: {street: "Evilstr. 44", zip: "66554", city: "Zahor"}
	}

 }

Keyspace
Das Keyspace ist die maximale Gruppierungsebene in Cassandra, d.h. sie gruppiert alle Column Families und Super Column Families zusammen. Normalerweise gibt es ein Keyspace für jede Anwendung. Es entspricht einer Datenbank in der relationalen Datenbanken Umgebung. Eine wichtige Einstellung ist der „replication factor“ und die „replica placement strategy“, die in weiteren Abschnitten beschrieben sind, und bestimmen jeweils den Faktor von Replicas bzw. die Anzahl der Kopien in dem Cluster und die Strategie wie die Replicas innerhalb des Clusters platziert werden. Also, wenn es Daten gibt, die unterschiedliche Bedürfnisse mit verschiedenen Einstellungen haben, dann sollten sie in verschiedenen keyspaces gespeichert werden.

Clustering


Cassandra Ring

Jeder Cassandra Server im Cluster wird als Cassandra-Knoten berücksichtigt. Jeder Cassandra-Knoten ist durch eine eindeutige Token identifiziert. Alle Token sind absteigend sortiert und formen einen Ring, wobei der letztere auf den ersten zeigt (Abbildung "Cassandra Ring"). Der Ring wird benutzt um die Position der einzelnen Daten durch die Abbildung ihre Schlüssel zu einer Token-Wert zu bestimmen.

Partitionierung

Für die Partitionierung der Daten werden verschiedene Partitioners genutzt. Die Wichtigsten sind die: RandomPartitioner und OrderPreservingPartitioner.

Der RandomPartitioner erzeugt ein MD5-Hash aus der Token und nutzt den generierten Hash um den Speicherort eines Schlüssels in dem Ring zu bestimmen. In der Tat, wird eine gute und gleichmäßige Verteilung der Daten erreicht.

Auf der anderen Seite, nutzt der OrderPreservingPartitioner kein Hash um den Speicherort des Schlüssels in dem Ring zu identifizieren. Stattdessen, vergleicht er den Schlüssel mit allen Token des Rings. Ein wichtiger Nachteil ist, dass diese Methode der Partitionierung zu einem unbalancierten Ring führen kann. Deswegen ist auf die kontinuierlich Anpassung der Knoten zu achten, um den Ring balanciert und die Daten gut verteilt zu halten.

Replication


SimpleStrategy

Wie in Keyspace erwähnt wurde, werden die Anzahl der Replicas gegen die Erstellung des Keyspace mit dem Parameter „replication factor“ bestimmt. Die Default-Einstellung ist 1, d.h. dass die Daten in einem einzelnen Knoten in dem Cluster gespeichert werden. Wenn die Zahl auf 4 erhöht wird, dann werden die Daten in vier verschiedenen Knoten gespeichert, also es werden vier verschiedene Kopien, im Falle eines Fehlers, verfügbar sein.

Es gibt drei Strategien für die Platzierung der Kopien im Cluster nämlich, die SimpleStrategy, NetworkTopologyStrategy und OldNetworkTopologyStrategy, die in Verbindung mit den Snitches verwendet werden. Die Snitches informieren Cassandra darüber, welche Knoten im gleichen Rack in einem Datacenter sind, so dass sie (Cassandra) in der Lage sein kann die Anfragen (lesend und schreibend) auf dem naheliegensten Knoten zu routen.

Die SimpleStrategy ist geeignet für Cluster, die sich in einem einzigen Datacenter befinden. Diese Strategie findet einfach den nächsten Knoten im Ring, und routet die Anfrage durch das SimpleSnitch.


NetworkTopology-&OldNetworkTopologyStrategy

Die NetworkTopologyStrategy und OldNetworkToplogyStrategy sind für Cluster, die in mehrere Datacenter gesplittet sind, geeignet. Die NetworkTopologyStrategy kann die Anzahl der Kopien für jedes Datacenter konfigurieren. Die Kopien werden in unterschiedlichen Racks im gleichen Datacenter platziert. Die OldNetworkTopoloyStrategy arbeitet ein bisschen anders: sie wird verwendet um eine der Kopien in einem anderen Datacenter, sowie den Rest der Kopien auf das laufenden Datacenter in unterschiedlichen Racks, zu platzieren. Es ist für den Einsatz dreier Kopien in zwei Datacenter optimiert (Abbildung "NetworkTopologyStrategy und OldNetworkTopologyStrategy")

Konsistenz

Cassandra gibt für jede Anfrage die Option für den Grad der Konsistenz. Dies bedeutet, dass spezifische Anfragen sehr konsistent sein können, während sie Geschwindigkeit opfern. Die verschiedenen Ebenen, die von Cassandra angeboten sind, haben unterschiedliche Bedeutungen im Schreiben und Lesen von Daten. Sie werden in den folgenden Tabellen beschrieben [1]

EbeneBeschreibung
ANYGewährleistet, dass die Daten in mindestens einem Knoten gespeichert sind.
ONEGewährleistet, dass die Daten in den Commit-Log von mindestens einer Replica gespeichert sind.
QUORUMGewährleistet, dass die Daten in einen Quorum von Replicas gespeichert sind.
ALLDie Daten müssen auf alle Replicas gespeichert werden, da sonst die Funktion scheitert.

Tabelle 1: Schreibkonsistenz

EbeneBeschreibung
ANYNicht Verfügbar.
ONELiefert die Daten von dem naheliegensten Knoten zurück (wie von Snitch konfiguriert)
QUORUMLiefert die neuesten Daten auf Basis der Zeitstempel, durch eine Ausführung eines QUORUM-Read, zurück.
ALLLiefert die neuesten Daten auf Basis der Zeitstempel, aus allen Replicas, zurück.

Tabelle 2: Lesekonsistenz

Das Quorum ist nur die halbe Anzahl von Replicas, die im Cluster existieren, plus 1, d.h. (N / 2) + 1. Dies gewährleistet, dass unabhängig von irgendwelchen Fehlern, die im Cluster vorhanden sind oder auftreten können, die aktuelle Lese- oder Schreiboperation gelingen wird und die neueste Version der angeforderten Daten zurückgegeben wird. Das Wichtigste ist, dass wenn die Summe der Anzahl der Schreib-Anfragen und der Anzahl der Lese-Anfragen größer als die Anzahl der Replicas, die im Cluster vorhanden sind, ist, dann heißt es dass eine sehr hohe Konsistenz erreicht ist. Folgendes Beispiel wird das QUORUM verdeutlichen:


QUORUM write/read

Angenommen es existiert ein Cluster mit 3 Replicas, bzw. N = 3 (siehe Abb. QUORUM write/read). Wenn eine QUORUM-Write-Anfrage in zwei Replicas ausgeführt wird, dann wird sichergestellt, dass die Daten auf zwei Replicas geschrieben wurden. Das Fragezeichen auf der dritten Replica, bedeutet einfach, dass während der Schreib-Operation deren Zustand unbekannt ist. Natürlich, wenn der Cluster korrekt funktioniert, werden die Daten asychron in wenigen Millisekunden kopiert. Auf der anderen Seite, wenn eine QUORUM-Read-Anfrage auf zwei Replicas durchgeführt wird und eine von ihnen die Replica mit dem Fragenzeichen ist, dann liefert das System immer die neuesten Daten zurück. In diesem Fall gibt es keine Kombination von zwei Replicas, womit eine QUORUM-Write-Anfrage oder eine QUORUM-Read-Anfrage nicht gelingen kann.

API

Thrift
Das Anfrage Modell der Cassandra ist RPC-orientiert und wurde mittels dem Thrift-Framework entwickelt. Das Thirft-Framework wird verwendet um RPC-Dienste zu entwickeln, und unterstützt viele Programmiersprachen wie C++, C#, Java, PHP, Erlang, Python, Ruby und viele andere[2]. Es ist aber nicht für die Entwicklung von Cassandra-Anwendungen empfohlen. Stattdessen gibt es mehrere High Level Clients, die im Wesentlichen als Middleware zwischen der Cassandra API und die Programmiersprache, den Dialog zwischen den Beiden vereinfachen.

High Level Clients

CQL
Seit der Version 0.8 ist die CQL (Cassandra Query Language) verfügbar, die Ähnlichkeiten mit der SQL hat. Sie unterstützt grundlegende Befehle um Daten zu verwalten (DM: Data Management), Daten anzufragen (DQ: Data Query) und Daten zu definieren (DF: Data Definition). Die wichtigsten Befehle sind:

  • USE: Es wird ein Keyspace als default Keyspace verwendet (DM)
  • SELECT: Es wird verwendet um Daten anhand Parameter abzurufen (DQ)
  • INSERT: Fügt Daten in den Spalten hinzu (DM)
  • UPDATE: Aktualisiert Daten (DM)
  • DELETE: Entfernt Daten (DM)
  • BATCH: Es wird verwendet um andere Anfragen in Transaktionen zusammen zu gruppieren (DM)
  • TRUNCATE: Entfernt alle Daten aus einer Column Family (DM)
  • CREATE: Erzeugt anhand von drei Unteroptionen (KEYSPACE, COLUMNFAMILY, INDEX) jeweils ein Keyspace, ein Column Family oder ein Index an der Column Family (DD)
  • DROP: Entfernt ein keyspace oder eine Column Family (DD)

Weitere Informationen sind unter hier verfügbar.

Quellen

Kategorie: Neue DB-Entwicklungen, NoSQL, Spaltenorientierte-DB, KeyValue-DB, C