Es gibt durchaus Fälle, in denen auch Anhänger von SQL-Datenbanken den Griff zu einer NoSQL-Datenbank wie Couch DB erwägen sollten. Linux-Magazin-Autor Stefan Wintermeyer schildert ein solches Szenario, in dem mehrere Couch-Instanzen effizienter miteinander kommunizieren als ihre SQL-Gegenstücke.
Angenommen eine Firma mit Standorten in Hamburg, München und Sydney will für die dortigen Mitarbeiter jeweils einen Datenbankserver aufsetzen, der die Datenbank darauf so synchronisiert, dass sie wie eine verteilte agiert. Mit klassischen Datenbanken wie PostgreSQL [1] und Maria DB [2] lässt sich das nicht leicht lösen. Das Problem ist die Latenz zwischen den Systemen.
Eine klassische relationale SQL-Datenbank lässt sich zwar in einen hochverfügbaren Cluster umbauen, der aber sollte sich im gleichen Raum oder Gebäude befinden. Der Grund ist simpel: Die Server müssen jeden Schreib- und Löschvorgang mit den anderen Servern synchronisieren.
Leider hilft hier keine Glasfaserleitung der Welt. Bandbreite ist nämlich sekundär, die Latenz erweist sich als wichtig. Bei freier Fahrt zwischen Hamburg und München braucht ein Ping dennoch gut 20 Millisekunden. Zwischen den Standorten Hamburg und Sydney wird gar ein Vielfaches davon gebraucht.
Diese Latenz verlangsamt alle Schreibvorgänge. Bei großen Datenbanken mit vielen Schreibzugriffen eskaliert das dann gerne. Und fällt die Verbindung mal aus, können Mitarbeiter nur noch am zentralen Standort (Master) arbeiten. Die anderen Standorte legen eine Zwangspause ein, bis die Verbindung wieder steht und die Systeme synchron laufen. Wie eine NoSQL-Datenbank wie Couch DB [3] das Problem in den Griff bekommen könnte, erklärt der nächste Absatz.
Nimm zwei
Generell gilt für verteilte Datenbanksysteme das so genannte CAP-Theorem [4]: Sie stellen maximal zwei der drei folgenden Eigenschaften zeitgleich zur Verfügung:
- Consistency (Konsistenz)
- Availability (Verfügbarkeit)
- Partition Tolerance (Ausfalltoleranz)
Klassische relationale Datenbanken bilden C (Konsistenz) und A (Verfügbarkeit) ab. Dafür haben sie ein großes Problem mit P (Ausfalltoleranz). Wenn der Master auf der einen Straßenseite steht, der Slave auf der anderen und ein Bagger das Kabel dazwischen trennt, lässt sich das Slave-System bis zum nächsten Sync nicht mehr nutzen.
Wer einen Datenbank-Cluster betreiben will, bei dem einzelne Nodes untereinander auch mal nicht erreichbar sind und auf dem trotzdem alle Nodes eine hohe Verfügbarkeit für die eigentliche Applikation mitbringen, braucht eine Lösung für Availability (Verfügbarkeit) und Partition Tolerance (Ausfalltoleranz). Hier bleibt demnach also die Konsistenz auf der Strecke.
Doch auch wenn es im ersten Moment irritierend erscheint, ist die mangelnde Konsistenz für viele Anwendungen tatsächlich gar kein echtes Problem. Denn es handelt sich hierbei um die zeitgleiche Konsistenz. So ist es etwa bei einem Adressbuch, das sowohl ein Handy als auch ein Server führen und syncen, nicht weiter dramatisch, wenn ein neuer Datensatz auf dem Handy erst 10 Sekunden später zur Verfügung steht.
Auftritt: Couch DB
In diesem Szenario betritt Couch DB die Bühne. Es bietet P und A an und verspricht zugleich, das schlussendlich (“eventually”) alle Nodes konsistent sind. Dabei darf es zum Beispiel schon mal passieren, dass ein Node, der gerade offline ist, einen nicht mehr aktuellen Datensatz an Bord hat. Sobald er aber wieder online geht, synchronisiert er alle Daten schnell und automatisch.
Bearbeitet eine Couch DB identische Datensätze zeitgleich auf verschiedenen – eventuell gerade nicht verbundenen – Servern, speichert die Datenbank jede Änderung mit einer eigenen so genannten Revisions-ID ab. Standardmäßig spielt die Datenbank auf allen Servern stets die gleiche Revision aus, aber die anderen sind abrufbar und lassen sich auf Applikationsebene zusammenführen. Couch DB arbeitet hier also ähnlich wie die Versionsverwaltung Git [5].
NoSQL
Couch DB ist eine Dokumenten-orientierte NoSQL-Datenbank. Die Vor- und Nachteile von NoSQL-Datenbanken wurden bereits häufig diskutiert, spielen aber für diesen Artikel keine Rolle (siehe auch Kasten “Warum ist Mongo DB populär und Couch DB nicht?”).
Warum ist Mongo DB populär und Couch DB nicht?
Fast jeder hat schon mal von der NoSQL-Datenbank Mongo DB [6] gehört, nur wenige kennen hingegen Couch DB. Das liegt gar nicht so sehr an technischen Gründen, denn tatsächlich unterscheiden sich die beiden wie Tag und Nacht. Mongo DB bedient im CAP-Theorem den Bereich CP, Couch DB den Bereich AP. Vielmehr rührt das aus der Sichtbarkeit der Software.
Die Macher der Mongo DB kümmern sich wesentlich intensiver um PR, Marketing und gute Dokumentation. Die Couch-DB-Entwickler begegnen Bitten nach einer besseren Dokumentation hingegen in der Regel mit dem Verweis auf das für alle offene Git sowie einer Aufforderung, einen Pull-Request mit einer besseren Dokumentation zu liefern.
Die Couch-DB-Dokumentation ist von Profis für Profis geschrieben. Sie überspringt gern mal einfache Zwischenschritte. Dass “einfach” aber nicht für jeden einfach ist, übersehen die Entwickler dabei geflissentlich. Erschwerend kommt hinzu, dass sich die Entwickler nicht die Mühe machen, Suchmaschinen per »rel=canonical« von einer alten auf eine neue Dokumentation zu leiten. Wie bei vielen anderen Open-Source-Projekten kümmern sich die Software-Urheber also zu wenig um Anfänger, die aber für das Wachstum wichtig sind.
Natürlich muss der Entwickler beim Einsatz von Couch DB auf das geliebte SQL als Abfragesprache verzichten, dafür bekommt er eine verteilte Datenbank, die über Städte, Länder und sogar Kontinente Netzwerkausfälle oder langsame Verbindungen übersteht.
Restful
Entwickler steuern Couch DB über ein Restful-HTTP-Interface [7] an. Wer die Datenbank installiert hat, bedient sie bei Bedarf auch über die Kommandozeile – auch hinter einem HTTP-Proxy. Eine frische Couch-DB-Installation zeigt mit folgender Abfrage alle lokal verfügbaren Datenbanken an:
$ curl -X GET http://127.0.0.1:5984/_all_dbs ["_replicator","_users"]
Eine neue Datenbank legt der Admin über das HTTP-Verb »PUT« an:
$ curl -X PUT http://127.0.0.1:5984/shop
{"ok":true}
Alle Abfragen und Befehle lassen sich damit per »GET«, »PUT«, »POST« und »DELETE« von der Kommandozeile aus ausführen.
Web-GUI Fauxton
Menschen, die Buntes mögen, erreichen die Couch-DB-Installation auf dem Rechner auch über einen eigenen Webclient, indem sie die URL »http://127.0.0.1:5984/_utils/« in den Browser der Wahl eintippen. Dieser Client heißt seit Version 2.0 Fauxton (vorher Futon, [8]) und ist in Couch DB 2.0 integriert. Es handelt sich um eine Javascript-Applikation, die wie »curl« auf der Kommandozeile auch nur per HTTP-Protokoll mit der Datenbank spricht. Wer will, installiert die neueste Version von Fauxton auch per »npm install -g fauxton«, startet den Client mit »fauxton«, um dann die URL »http://localhost:8000« einzugeben (Abbildung 1).
Datensätze anlegen
Couch DB arbeitet Dokumenten-orientiert. Da es kein festes Schema für eine Datenbanktabelle gibt, muss sich der Entwickler auch keine Gedanken um deren Struktur machen. Es genügt, ein Dokument anzulegen und den Inhalt im Json-Format zu füllen. Im fiktiven Onlineshop legt der Autor das Produkt »Apfel« im Web-GUI an (Abbildung 2).
Beim Anlegen eines neuen Datensatzes füllt Fauxton automatisch den Wert »ID« mit einem Universally Unique Identifier aus. Wer eine eigene ID verwenden möchte, kann beim Anlegen des Dokuments diese statt des Standardwerts verwenden. Wer will, kann aber auch die ID »Apfelmus« vergeben.
Vergibt der Admin keine ID, weist Couch DB automatisch eine zu. Bei selbst erstellten IDs muss er jedoch darauf achten, dass die IDs über den gesamten Datenbank-Cluster hinweg einzigartig sind. Eine neue Uniqe ID fordert er bei Bedarf explizit bei Couch DB über eine »GET«-Anfrage an:
$ curl -X GET http://127.0.0.1:5984/_uuids
{"uuids":["1ce330a867a803fd10082c4513003af2"]}
Nach dem Anlegen lässt sich der Inhalt des Dokuments unter der URL »http://127. 0.0.1:5984/shop/1ce330a867a803fd10082 c451303e6c6« mit jedem Browser als Json-Dokument abrufen (Abbildung 3). Dabei steht »shop« für den Namen der Datenbank und die lange ID für einen Universally Unique Identifier (UUID). Natürlich ist es auch möglich, den Inhalt in Fauxton zu betrachten.

Abbildung 3: Das zum Apfel gehörige Json-Dokument lässt sich dann auch direkt im Browser betrachten.
An dieser Stelle fällt auf, dass das Dokument nicht nur ein Feld »_id« für die ID, sondern auch ein Feld »_rev« für die Revision besitzt. Das letzte schreibt Couch DB automatisch mit jeder Veränderung neu. Dabei muss der Client beim Schreiben auch stets die alte Revision mitliefern. Das schafft analog zu Git die Möglichkeit, in einem Dokument in die Vergangenheit zu reisen.
Compaction
Wie es bei Zeitreisen üblich ist, gilt es auch hier, einen Tribut zu entrichten. Was das Plutonium in “Zurück in die Zukunft I” ist, das ist in diesem NoSQL-Szenario der Festplattenplatz, da Couch DB ja jede Revision speichern muss. Normalerweise empfiehlt es sich deshalb, die nicht mehr benötigten Revisionen in regelmäßigen Abständen zu löschen.
Dieser Löschprozess heißt Compaction und lässt sich mit »VACUUM« in SQlite vergleichen. In seinem Verlauf erzeugt Couch DB eine neue Datei mit der Endung ».compact« und schreibt in diese Datei alle benötigten Revisionen. Anschließend löscht es die alte Datei und ersetzt die Originaldatei.
Am Ende speichert Couch DB dabei alte Revisionsdaten als kleine Metadaten. Diese heißen Tombstones. Wie weit in die Vergangenheit dieser Prozess reicht, lässt sich per »_revs_limit« in der URL bestimmen. Der Befehl
$ curl -H "Content-Type: application/json" -X POST http://localhost:5984/shop/_compact
{"ok":true}
startet dann den Prozess für eine Datenbank mit dem Namen »shop«.
Validierungen
Der Alptraum jedes Datenbankverantwortlichen sind unvollständige und damit invalide Datensätze. Bei Couch DB muss er sich nicht auf die Applikation verlassen, sondern schreibt in der Datenbank beliebig komplexe Validierungsregeln via Javascript. Will er für die »product«-Datensätze sicherstellen, dass die immer einen Namen für das Produkt enthalten, setzt er das mit dem Javascript-Programm aus Listing 1 um.
Listing 1
product-Datensätze validieren
01 function(newDoc, oldDoc, userCtx) {
02 if (newDoc.type == "product") {
03 if (!newDoc["name"]) {
04 throw({forbidden: "missing name" });
05 }
06 }
07 }
Dieses Programm legt er als einzelne Zeile in einem so genannten Design-Dokument namens »validate_doc_update« im Bereich »_design« ab. Auf der Kommandozeile sieht das dann – man beachte die Escapes (»\«) – so aus:
$ curl -X PUT http://127.0.0.1:5984/shop/_design/product_validation -d '{"validate_doc_update": "function(newDoc, oldDoc, userCtx) { if (newDoc.type == \"product\") { if (!newDoc[\"name\"]) { throw({forbidden: \"missing name\"}) } } }"}'
{"ok":true,"id":"_design/product_validation","rev":"1-a06459ca8faaa35d28d6c86e3e594cb6"}
Ein Bandwurm-Befehl, wobei der Teil – beginnend mit »”function…« bis zum »}) } } }”« – aus Listing 1 stammt.
Suchen
Es gibt eine Vielzahl von Möglichkeiten, innerhalb einer Couch-DB-Datenbank zu suchen. Vom einfachen »_find« bis zur komplexen Map-Reduce-View. Die Möglichkeiten übersteigen bei Weitem die von SQL, allerdings ist die Einstiegshürde auch viel höher. Interessierte müssen sich anfangs ein wenig in Javascript einarbeiten und zusätzlich auch in die Arbeitsweise von Views eintauchen.
Basic Setup
Eine Rechteverwaltung ist im Normalbetrieb ebenfalls sinnvoll. In Fauxton lässt sich unter »Setup« auch ein Admin-Account anlegen (Abbildung 4).

Abbildung 4: Im Normalbetrieb sollten Admins Couch DB mit einem Admin-Account betreiben. Der lässt sich über eine Maske anlegen.
Wer einen Account »egon« mit dem Passwort »1234« anlegt, greift so auf die Datenbank »shop« zu:
$ curl GET http://egon:1234@localhost:5984/shop
Wer will, authentifiziert sich über ein Cookie. Im Produktivbetrieb ergibt zudem SSL Sinn, wenn Nutzer von außen auf den Couch-DB-Server zugreifen.
Pouch DB und Offline First
Moderne Webseiten und Webapplikationen verfolgen häufig einen Offline-First-Ansatz. Die Applikation lässt sich auch dann problemlos nutzen, wenn das Handy im Tunnel den nächsten Funkmast nicht mehr erreicht und daher offline geht. Für solche Anwendungen gibt es die Javascript-Datenbank Pouch DB [9], Inspiriert von Couch DB spricht sie das gleiche Protokoll und ist in der Lage, sich mit einem Couch-DB-Server zu synchronisieren. Das Handy wird damit Teil des Couch-DB-Datenbankverbunds.
Für wen taugt Couch DB?
Wer mit PostgreSQL glücklich ist, braucht sich nicht nach einer anderen Datenbank umzusehen. Nur wer geografisch verteilte Datenbanken mit einer hohen Verfügbarkeit benötigt, der sollte auf einer Couch DB Probe sitzen. Das Gleiche gilt für Entwickler, die an Offline-First-Webanwendungen arbeiten und dafür einen stabilen und schnellen Datenbank-Sync anstreben. In diesem speziellen Szenario gibt es aktuell wahrscheinlich nichts Besseres als Couch DB in Kombination mit Pouch DB.
Infos
-
PostgreSQL: http://www.postgresql.org
-
Maria DB: https://mariadb.org
-
Couch DB: https://couchdb.apache.org
-
CAP-Theorem: https://de.wikipedia.org/wiki/CAP-Theorem
-
Konflikt-Management in Couch DB: http://docs.couchdb.org/en/stable/replication/conflicts.html
-
Mongo DB: https://www.mongodb.com
-
Marcus Nasarek, “Spätzünder”: Linux-Magazin 06/17, S. 66
-
Fauxton, vormals Futon: https://github.com/apache/couchdb-fauxton
-
Pouch DB: https://pouchdb.com








