am 19. Oktober 2009
Wenn in der Webentwicklung etwas so gemacht wird, weil es schon immer so gemacht wurde, ist das im Allgemeinen ein guter Moment aufzuhorchen. Ich frage mich, von welchem “schon immer” da die Rede ist? Das “schon immer” von vor 10 Jahren, als alle Schichten einer Anwendung noch ein trautes Beisammensein in einer PHP-SQL-HTML-Datei zelebrierten oder das von vor 20 Jahren, als ein smarter Typ am CERN auf die Idee kam, Dokumente mittels einfachem Markup zu strukturieren und miteinander zu verlinken (und Anwendungen monolithische Felsklötze auf unseren stationären Desktopcomputern waren)?
Seitdem ist zum Glück viel passiert und die Strategien zur Planung und Implementierung von Webanwendungen sind kontinuierlich vielfältiger geworden. Nur die Grundannahme, dass für die Implementierung der Persistenzschicht ein relationales Datenbankbetriebssystem zum Einsatz kommt, scheint als unverrückbarer Pfeiler alle Entwicklungen zu überdauern. – Auch bei mir. Das habe ich schließlich schon immer so gemacht.
If it ain’t broken, …?
Aber warum sollte ich denn überhaupt etwas anderes wollen? Relationale Datenbankbetriebssysteme sind stabil, ausgereift und in mannigfaltiger Ausprägung erhältlich.
In Chaosradio Express, Folge 125, wird in meinen Augen ziemlich gut erklärt, was das Problem ist: relationale Datenbankbetriebssysteme lösen Probleme, die so in vielen (Web-) Anwendungen gar nicht vorhanden sind – und das Potential komplexere Probleme zu lösen bringt zumeist eine komplexere Bedienung mit sich. Konkret bedeutet das, dass es in vielen Fällen nicht nötig ist, Daten bis in die Letzte Normalform zu zerlegen, weil alles, was uns interessiert ein User-Objekt mit ein paar Eigenschaften und seine Beziehung zu anderen Usern ist.
Hinzu kommt, dass relationale Datenstukturen in einer objekt-orientierten Welt oftmals ein Fremdkörper sind. Zugegeben, für die Überbrückung dieser Unterschiede gibt es dank vielfältiger Objekt-Relationaler-Mapping-Frameworks mittlerweile überzeugende Lösungen. Am Ende des Tages bleiben sie jedoch der Versuch, Dinge anzugleichen, die eigentlich nicht gleich sind. Und das kostet in der Regel. Und zwar Performance.
Und nicht zuletzt sind Web-Anwendungen oftmals dynamischen Entwicklungen unterworfen und es ist anfangs nicht immer möglich, die finale Datenstruktur bis ins letzte zu definieren. Datenschemata machen daher nur bedingt Sinn, da sie etwas formalisieren, das an dieser Stelle so gar nicht gebraucht wird. Wird beispielsweise zu irgendeinem Zeitpunkt im Lebenszyklus einer Anwendung beschlossen, dass Nutzer jetzt auch eine Lieblingsfarbe haben können, ist es nicht wünschenswert in die Struktur einer produktiv genutzten Datenbank einzugreifen, in der entsprechenden Tabelle ein Feld hinzuzufügen, um dann eine Vielzahl von leeren Feldern zu haben.
Öfter mal was Neues
Zeit also mal einen Blick auf alternative Ansätze zu werfen, denn es kommt durchaus Bewegung in die Sache. Mehr und mehr Alternativen betreten die Arena. Sei es das von Facebook entwickelte Cassandra, MongoDB oder das altbekannte MemcacheDB. Allen gemein ist der Verzicht auf das Paradigma des Strukturieren von Daten mittels Relationen. Im Allgemeinen handelt es sich um einfache Key => Value Speicher für strukturierte und semi-strukturierte Daten. Das aber außerordentlich leistungsfähig. Laut einer Präsentation von Avinash Lakshman (Facebook) schreibt Cassandra beispielsweise mehr als 2500 Mal schneller als MySQL!
Welche Anwendung die beste, leistungsfähigste und sexieste ist, ist wie immer ein heiss diskutiertes Thema. Felix Geisendörfer von Debuggable hat sich mit Insert Benchmarks in CouchDB beschäftigt, die anschliessend mit MongoDB verglichen wurden. Ein wirklich lesenswerter Artikel zum Thema ist Alternatives to SQL Databases von Ian Ward.
CouchDB
Der Shooting-Star am nicht-relationalen Datenbankhimmel hört auf den prägnanten Namen CouchDb und wird von der Apache Software Foundation betreut. Die Software wird beschrieben als “verteilte, fehlertolerante und schemafreie, dokumentenorientierte Datenbank”. Statt SQL erfolgt die Kommunikation mit CouchDB über eine RESTful JSON API. Das bedeutet, dass man beispielsweise für eine einfache Abfrage eine URI via HTTP aufruft und als Antwort kein Rowset, sondern ein JSON formatiertes Objekt erhält. Ähnlich funktioniert das Anlegen und Aktualisieren von Datensätzen. Hier wird ein JSON-Objekt an eine URL geschickt. Die Arbeit mit CouchDB hat daher weniger etwas von einer traditionellen Datenbank, sondern fühlt sich vielmehr an, als würde man mit einem WebService kommunizieren.
Da ein Datenspeicher jedoch mehr beherrschen sollte, als einfache CRUD-Operationen, ist es zudem möglich Views zu definieren. Dabei handelt es sich um JavaScript-Funktionen. Was sich im ersten Moment ein wenig merkwürdig anhört, entpuppt sich bei genauerer Betrachtung als extrem mächtiges Werkzeug. Eine solche Funktion definiert welche Key => Value Paare aus der Datenbank geholt werden sollen und wie sie sortiert sein sollen. Der SQL-Befehl
SELECT LastName, FirstName, FirstName, Address FROM table WHERE type = 'customer'
entspricht dabei ungefähr folgendem Beispiel aus dem CouchDB-Wiki
function(doc) {
if (doc.Type == "customer") {
emit(doc.LastName, {FirstName: doc.FirstName, Address: doc.Address});
}
}
Die Funktion definiert für jede Zeile eine einen Key und einen Value und sortiert das Ergebnis an Hand des Keys. Der Trick: der Key muss nicht, wie hier, aus einem einfachen Strung bestehen. “CouchDB allows arbitrary JSON structures to be used as keys. You can use complex keys for fine-grained control over sorting and grouping.”
PHP-Integration
Da die Kommunikation über HTTP und REST erfolgt, ist zunächst einmal jede Form von HTTP-Request geeignet, um mit CouchDB zu arbeiten. Im einfachsten Fall kann das sogar ein Aufruf mittels file_get_contents() sein. Üblicherweise empfiehlt es sich aber natürlich ein wenig grundsätzlicher an die Sache heranzugehen und sich einen REST-Client selber zu schreiben oder eine geeignete Bibliothek zu nutzen.
Glücklicherweise gibt es mittlerweile Bestrebungen, CouchDB weitergehend in PHP-Anwendungen zu integrieren. Unter Anderem liegt im Zend Community Wiki seit einiger Zeit ein vielversprechendes Proposal namens Zend_Couch von Matthew Weier O’Phinney vor, Shahar Evron von PrematureOptimization hat mit Sopha eine ziemlich schlanke Abstraktion veröffentlicht und neben einigen weiteren Bibliotheken gibt es PHPillow. Im Gegensatz zu einigen anderen Ansätzen, macht diese Bibliothek bereits einen relativ ausgereiften Eindruck (sofern man bei Alpha-Releases von Reife sprechen kann). Aus diesem Grund soll im nächsten Teil die grundsätzliche Arbeitsweise mit CouchDB an Hand von PHPillow demonstriert werden.