Umdenken bei NOSQL: Datenkonsistenz in RavenDB

image.png

Bereits im Einstiegspost wurden auf die Vor- aber auch auf die Nachteile von einer NoSQL Datenbank (in meinem Fall RavenDB) eingegangen. Die größte gedankliche Hürde ist das die Datenkonsistenz nicht so einfach sicherzustellen ist, wie in einer klassischen Datenbank.

Ich sprech jetzt mal von RavenDB, weil ich nicht wirklich weiß ob dies bei anderen NoSQL Datenbanken ähnlich ist. Falls ich bei dem geschriebenen auf dem Holzweg bin, sagt mir einfach Bescheid Zwinkerndes Smiley

Wo liegt das Problem?

In einer klassischen Datenbank kann ich Verknüpfungen zwischen Tabelleneinträgen herstellen. Der heilige Gral der Schulweisheit ist eine Datenbank in der 3. Normalform. Beispiel: Ein Kunde macht Bestellungen und kauft dabei ein Produkt.

In Tabellenform gedacht hätten wir nun eine Kunden-Tabelle, eine Produkt-Tabelle und eine Bestellung-Tabelle mit der Referenz zum Kunden und zu einem Produkt. Das Beispiel kann man noch beliebig aufblähen und kennt wahrscheinlich jeder Zwinkerndes Smiley

Es gibt kein Schema…

In RavenDB ist es etwas anders. Dort gibt es keine direkten Verknüpfungen zwischen Dokumenten. Jedes Dokument steht für sich alleine. Siehe auch dieses Bild:

image

In der RavenDB Doku ist dieser Abschnitt dazu besonders interessant und für Einsteiger empfehlenswert. Natürlich gibt es auch hier “Verbindungen”, allerdings sind diese hier deutlich weicher als in einer klassischen Datenbank. Unter “blogs/9431” gibt es die Verbindung zu dem “users/ayende” Dokument, jedoch lädt RavenDB nicht automatisch irgendwelche Daten nach. Dieses Verhalten kennt man von diversen ORMs, welche über User.Orders.Products.First() witzige SQL Statements erzeugen und die Datenbank unter Last setzt Zwinkerndes Smiley

Hat man dadurch nicht Daten doppelt?

Hier fängt meine “gedankliche Blockade” an – jedoch ist die doppelte Datenhaltung in diesem Fall beabsichtig: Daten sollen doppelt gehalten werden. Wenn wir die Tags und Kategorien an einem Post brauchen um diesen im Frontend darzustellen, dann hängen wir diese Daten da auch mit ran.

(Natürlich kann man solche Sachen auch mit klassischen Datenbanken machen und Daten doppelt vorhalten oder “cachen” – allerdings macht man dies meist aus Performancegründen und nicht weil es so schön elegant ist Zwinkerndes Smiley)

Updateszenarien

Schwierig wird es natürlich nun wenn ich eine Kategorie komplett umbenennen will. In diesem Fall muss man wohl über alle Posts gehen und schauen ob die Kategorie noch dran ist. image

An dieser Stelle muss man natürlich entscheiden: Macht es Sinn die Kategorien überall umzubenennen? Wenn wir das Kunde/Bestellsystem Beispiel von oben nehmen: Der Kunde kauft zum Zeitpunkt A ein Produkt namens “Nimbus 2000”. Nun ändere ich zum Zeitpunkt B aber den Namen des Produkt in “Nimbus 2010”. Jetzt sieht es allerdings in der Datenbank so aus als hätte der Kunde den “Nimbus 2010” gekauft. Interessanter wird es noch, wenn ich das Produkt löschen möchte…

Zum Teil macht es auch extrem Sinn die Daten “doppelt” zu halten. Nicht nur von der Performance, sondern auch vom fachlichen.

 

Was passiert wenn ich ein Feld hinzufüge oder entferne? Wie behalte ich da die Kontrolle?

Diese Frage kam vorhin bei Golo Roden auf. Was passiert, wenn ich nun zu einem Produkt noch zusätzliche Daten abspeichern möchte? Oder ich möchte ein bestimmtes Merkmal nicht mehr speichern? Wie geht RavenDB damit um?

Um es mal einfach zu sagen: RavenDB ist es egal – es serialisiert am Ende nur Objekte als JSON. Alle Daten eines Dokumentes sind als JSON abgespeichert. Da gibt es kein Schema. Wenn ein Property hinzukommt, dann wird es beim Serialisieren berücksichtig. Wenn ich auf “leere” oder “nicht vorhandene” Felder zugreifen möchte bekomme ich in RavenDB einfach ein leeres Objekt zurück. In diesem Fall muss ich mich in der Applikation darum kümmern.

Wenn ein Property entfernt wird, dann wird es im Prinzip auch ignoriert und beim nächsten Speichern wird es auch entfernt – weil das Property nicht mehr vorhanden ist und die alten Daten überschrieben werden.

Schwieriger wird es wenn Properties umbenannt werden, aber auch gibt es ein Extension Point.

Wer vor diesen Problemen steht, sollte nochmal ein Blick auf diesen Blogpost von Ayende werfen:

RavenDB Migrations: Rolling Updates

Auch sehr interessant der Blogpost zu Migrations.

Aller Anfang ist schwer…

Definitiv ist bei NoSQL Datenbanken ein Umdenken erforderlich. So ganz klar und geheuer ist es mir ja noch nicht ganz, aber ich schau immer mal bei der RavenDB Demoapp Raccoon Blog wie der Schöpfer es da gemacht hat Zwinkerndes Smiley


Kick It auf dotnet-kicks.de
Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf dem Laufenden bleiben willst, abonniere unseren RSS Feed oder folge uns auf Twitter.

About the author

Written by Robert Mühsig

Robert Mühsig (@robert0muehsig) ist Webentwickler und beschäftigt sich mit Web-Frameworks (vor allem dem ASP.NET MVC Framework) und scheut sich auch nicht vor Javascript. Ansonsten bloggt er über all jene Probleme, die ihm über den Weg laufen. Seit 2008 ist er Microsoft MVP für ASP.NET und er arbeitet bei der T-Systems Multimedia Solutions GmbH in Dresden. Treffen kann man ihn online via Twitter (@robert0muehsig) oder dieser Seite oder bei der .NET User Group Dresden.

9 Responses

  1. Tja, ein Umdenken ist hier wirklich erforderlich. Mit NoSQL muss man sich andere Gedanken machen bzgl Denormalisierung bzw der Frage, was sind meine Root-Aggregates? Ich spiele mit RavenDB seit über einem Jahr rum, und mir kommt NoSQL mittlerweile wesentlich “natürlicher” vor als ein RDBMS.

    > Unter “blogs/9431” gibt es die Verbindung zu dem “users/ayende” Dokument, jedoch lädt RavenDB nicht automatisch irgendwelche Daten nach

    Auch das hat Ayende sehr elegant gelöst: Wenn ein Dokument A eine Referenz auf ein anderes Dokument B hält, kann ich schon beim Laden von A anweisen, dass auch B geladen werden soll, siehe http://ravendb.net/faq/includes

    Reply
  2. Noch ein weiterer Punkt zum Umdenken: Die Denormalisierung macht vor allem Sinn, wenn Du selten Daten änderst.
    Um bei Deinem Beispiel zu bleiben: Der Namen des Artikels “Nimbus 2000″ wird sich wohl eher selten ändern, d.h. der Fall, dass Du ein vorhandenes Dokument aktualisieren mußt, ist wesentlich seltener, als dass Du eine Bestellung laden musst. Gegenüber einem klassischen, normalisierten RDBMS sparst Du Dir also die leidlichen JOINs, da Du alle Informationen bereits in einem Dokument beisammen hast. Die Updates dagegen treten sehr selten auf.
    Kurzum: wenn die Zahl der Reads die Writes stark übersteigt, ist NoSQL sehr interessant.

    Reply
  3. Dein Artikel Robert drückt die Gehirnwäsche aus, die jeder mitmacht, der mit SQL zu NoSQL kommt. Es ist so, als wenn du jahrelang Single warst und dann anfängst dein Leben mit einer Mietze zu teilen.. es erfordert radikales Umdenken ;o)

    Die von dir diskutierten Updates auf Dokumente sind eigentlich gar kein Problem. Hier kann man elegante Lösungen finden. Stell dir vor, du änderst nachträglich den Tag „C#“ auf „I love C#“ deiner Blog Dokumente.. nehmen wir mal an du hast viele, sehr viele Blogs bereits geschrieben. Mehr als 1.000.0000. Dann ist ein Update per Pull-In sehr „teuer“ und du müsstet jedes Dokument „anfassen“. Geht aber auch anders. Stell dir vor, du führst die Änderungen an den Tags in einer separaten Datenbank mit und jedes Mal wenn ein User ein Blog öffnet, gleicht dein System vor der Anzeige alle ausstehenden Änderungen an dem Blogdokument ab, sofern notwendig… das ist cool, weil sehr günstig; erfordert wenig Operations und ist schnell. Das Prinzip dahinter sind nicht neu – „lazy write“.

    Das eigentliche Problem sind gar nicht so sehr die Updates… Nehmen wir mal an du hast sehr aktive User und binnen 14 Tagen sind 20% alle Blogeinträge durch das „Update-per-Request“ (oder lazy write) Verfahren bereits aktuell, also auf „I love C#“ aktualisiert. Was aber, wenn du nach 14 Tagen anfängst deine Datenbank zu fragen: „Gib mir alle Blogs mit dem I love C# Tag“. Korrekt, jetzt wird heikel, weil 80% der Dokumente noch C# als Tag gespeichert haben… was nun?

    Auf jeden Fall nicht das Ende der Welt.. auch hier hast du wieder viele Möglichkeiten. Stell dir vor du führst nicht nur Änderungen an Dokumenten separat mit, sondern auch Änderungen an deren Index. Also du weißt, wenn ich die Anfrage „gib mir alle Blogs mit Tag I love C#“ stelle, dann muss ich auch die Anfrage „gib mir alle Blogs mit Tag C#“ stellen, andernfalls ist das Ergebnis inkonsistent.

    Ich glaube die größte Herausforderung für uns Klassiker aus der SQL Welt ist, dass man sich von seinem 100% picke feinen Datenbankmodellen verabschieden muss. Dokumentendatenbank haben ehr etwas vom World Wide Web.. ändert sich heute eine Webpage, dann wird google erst in ein paar Tagen darauf reagieren… ändert jemand heute das Tag in seinem Blog (aus dem Beispiel), dann kann es sein dass seine Blogdokumente erst Jahre später alle aktuell sind (rein theoretisch). Aber wenn der Nachverfolgungs- oder Änderungsmechanismus stimmt ist es nicht weiter schlimm. Und stell dir mal vor, es gibt nach zwei Jahren immer noch ein Blogdokument, dass über den alten Tagnamen C# verfügt…. zum Glück haben wir damals kein Update auf dieses Blogdokument gemacht, weil es sowieso niemand gelesen hat… cool wir haben damit Rechenzeit, Strom und Energie gespart. Wow. Wie man sieht ist NoSQL sogar umweltfreundlich;)

    Oder dir gefällt die Idee nicht, die Indizes über eine Art Nachverfolgungsalgorithmik zu lösen? Okay, dann kannst du die Indexierung der „Raven“ Dokumente z.B. über eine In-Memory Datenbank wie Redis selbst immer aktuell mitführen. Das hier sind natürlich nur Ansätze und müssen je nach Anforderung durchdacht werden… klar!

    Und dann hast du ja noch die „includes“, wie von meinem Vorschreiber und Namensvetter bereits erwähnt. Für dessen Hinweis ich dankbar bin… man lernt nie aus. Allerdings denk ich mir jetzt, sollte man es damit nicht übertreiben, um den Vorteil einer Dokumentenorientierten Datenbank nicht zu verschenken.

    Reply
    • Vielen Dank für dein Kommentar – wie du bereits geschrieben hast: Die “Inkonsistenten” muss man selber managen oder es wird einfach etwas “unsauberer” (ob das gut oder schlecht ist, sei dahingestellt ;) ).
      Wo man früher immer auf das Konzept ACID gepocht hatte, kommt man immer mehr Richtung BASE (http://en.wikipedia.org/wiki/Eventual_consistency).
      Auf alle Fälle: Spannend.

      Reply
    • Die Idee mit dem Index funktioniert so leider nicht, weil lucene keine interceipts kann, d.h. man kann also nicht einfach eine query formulieren mit “c#” oder “i love c#” und das selbe ergebnis erwarten, denn es ändert sich dabei die relevanz der dokumente (lucene-dokumente) -> sprich: die reihenfolge ist anders. Je nach Appkikation kann das egal sein, oder eben auch nicht. Bei ‘seriösen’ Businessanwendungen ist es meistens nicht egal, insofern bleiben dann die rolling updates nur eine nette Idee.

      RavenDB ist cool, ja. Nach mehreren realen Projekten und auch ein bisschen Erfahrung im Team, kann ich allen aber nur dringend raten sich vorher genau zu informieren, auf was man sich da einlässt. Der Performance-Benefit kommt nicht umsonst und der Mythos mit der verkürzten Entwicklungszeit verpufft auch ganz schnell, wenn man das erste mal versucht eine Summe über Rechnungsdokumente zu machen, sodass man sich den Gesamtumsatz ausrechnen kann.

      Reply
  4. double post!? grrr… sorry… its late:o)

    Hi Daniel,

    hab deinen Post gelesen und gib dir kurz ein Update. Ich arbeite seit 3 Monaten mit im Research, um für ein Projekt eine passende coSQL (wie MS die NoSql Welt neuerdings nennt) Datenbank für unsere Ansprüche zu evaluieren.

    Zunächst kann ich deine Anmerkung in Bezug auf Aggregation mit RavenDB teilen; nach vielen Prototypen und Tests ist RavenDB hierfür gänzlich unausgereift – oder besser- schlicht weg nicht dafür designt worden. In deinem Beispiel für jeden Umsatzreport einen Map/Reduce über den Cluster zu schicken ist nicht nur aufwendiger als ein netter SQL Statement, sondern auch wesentlich „teuer“. Das erklärt vermutlich auch die langanhaltende Blogreihe von ayende „Whats wrong here?“ bei der das Northwind Beispiel für RavenDB diskutiert wird. Wir sind nach unserer RavenDB Begeisterung dann zu CouchDB gekommen und fanden dort (neben einem ACID Model, was für Geschäftsanwendung durchaus interessant sein kann) die Views, die das Problem der Aggregation wesentlich vereinfachen; diese werden auch über den Cluster repliziert und sind aufgrund Ihrer Persistenz wesentlich performater als jedesmals mittels M/R die Daten neu durchwühlen zulassen.

    Auch cool und da sind wir derzeit dran ist Couchbase (eine Komposition aus Membase Key/Value Storage, der seine Daten mittels CouchDB persistiert). Dort gibt es – und das ist wirklich abgefahren – nun UNQL, eine SQL ähnliche Sprache für unstrukturierte Datenbanken. Da dieser Standard zusammen mit Microsoft entwickelt wurde und wird (allerdings nicht nur mit Couchebase alleine) und ich vor kurzem diesbezüglicher einer interessanten Key Note beiwohnen durfte, darf man ruhig die Prognose wagen, das Unql zu dem SQL Ersatz für coSQL und defacto-Standard für co(oder no)SQL Datenbanken „werden könnte“ (weiß es nicht sicher, aber denke Unql ist auch in CouchDB impl.)

    Diesbezüglich absolut deiner Meinung, wer sich blindlinks auf einen DocumentStore stürzt, nur weil hier die Latenzzeit atemraubend sein kann oder LinQ unterstützt wird, der kann böse Überraschungen – hoffentlich – überleben; mich hats da genauso erwischt (du hättest mich noch vor zwei Wochen über RavenDB sprechen hören sollen – an dieser Stelle – es ist ein ausgezeichnetes Produkt… doch prüfe wer sich ewig binde).

    Ein letztes Wort –ganz kurz, will Roberts Blog nicht volltexten – zu den Rolling Updates. In einem Posts von dir Daniel „How to handle relations in RavenDB“ ist kurz das Konzept „Denormalize your references (partly)“ besprochen; hier kann ein Rolling Update-Konzept tatsächlich ein Implementierungsweg sein (das Konzept ist in ähnlicher Form in der REST Architektur für das Caching implementiert; If-None-Match-Header oder If-Modified-Since-Header). Wenn mich jemand fragen würde ob Rolling Updates für eine Bloganwendung okay sind, dann denke ich ja.

    Happy coSQL und beste Grüße,Tom

    Reply
    • Tom, danke für deine wertvollen Tipps und Anregungen. Dein Kommentar war wirklich interessant zu lesen!

      Wegen dem Namen – habe dieses coSQL jetzt das erste Mal gehört. Wäre interessant wenn sich das durchsetzen würde, kann mir das aber überhaupt nicht vorstellen. Abwarten und Tee trinken… :D

      Reply
      • @Tom/Daniel: Lagen die Probleme eher bei RavenDB oder generell beim Konzept der DocomentDBs? Ich habe bislang nur ein kleines Hobby-Projekt und bin noch in der “alles-ist-gut-Phase”. coSQL muss ich mir auf alle Fälle merken ;)

        Reply
        • Keine Probleme. Nach wie vor würde ich eine überwiegende Anzahl neuer Projekte mit RavenDB beginnen. Aber ein bisschen Ernüchterung schon, dass Dokumentendatenbanken nicht _der_ Universalhammer sind und nach der überschwinglichen Euphorie auch Ecken und Kanten zum Vorschein kommen, die einem gute Gründe liefern eben nicht eine Dokumentendatenbank zu wählen und stattdessen bei einer relationalen Datenbank (PostgreSQL ist eine echte Alternative, btw.) zu bleiben.

          Reply

Comment on this post

Letzte Posts

  • image.png
    Chocolatey–apt-get für Windows

    Durch Zufall bin ich auf das Tool “Chocolatey” gestoßen. Wer die Website sich anschaut, wird evtl. eine Verwandschaft mit NuGet ausmachen. Was macht Chocolatey? Chocolatey ist ein “Maschine Package Manager”, das bedeutet, dass man für seine Maschine einfach Tools runterladen und Updaten kann – direkt über die Konsole. Was ist der Unterschied zu NuGet? NuGet ...

  • image.png
    SASS, LESS & Coffeescript in Visual Studio mit der Web Workbench

    CSS und Javascript sind die “kleinste” Schnittmenge von allen Browsern für die Erstellung von Web-Applikationen. Leider geht dabei etwas komfort verloren, daher lieben alle Webentwickler jQuery! SASS und LESS sind zwei Varianten, wie man “schöner” CSS schreiben kann und Coffeescript versucht Javascript Entwicklung zu vereinfachen. Aber immer der Reihe nach… Was ist SASS? SASS steht ...

  • image.png
    Code-Inside Sample nun auf GitHub: Google Code zu GitHub Migration

    Seit einiger Zeit habe ich Beispielcode auf Google Code bereitgestellt. Einfach nur noch weg von Google Code O-Ton damals war: Ich hatte mich für Google Code entschieden, weil ich hoffe dass früher oder später die Google Code Suche nutzbar ist und es dadurch wenigstens ein kleiner Mehrwert entsteht. Allerdings wirft es momentan noch ein Fehler. ...

  • image.png
    Windows-8-Hackathon @Night in Leipzig

    Hacken (=Entwickeln, nichts böswilliges!), Grillen und mitten in der Nacht fachsimpeln? Dann ist vielleicht der Windows-8-Hackathon was für dich. Der Hackathon wird vom 15. Juni (ab 19:00) bis zum 16. Juni (bis in die frühen Morgenstunden) in Leipzig stattfinden.  Mit dabei sind auch Darius Parys und Tom Wendel von der Microsoft Deutschland. Thematisch (wie der ...

  • image.png
    Einstieg in Redis on Windows & Redis mit .NET benutzen

    Redis gehört zu den NoSQL Datenbanken und ist dort in der Familie der Key-Value Stores zu finden. Redis wird oft mit “Blazing Fast” betitelt und laut dem Stackoverflow Thread soll es im Vergleich zu MongoDB zweimal (beim Schreiben) und sogar dreimal (beim Lesen) so schnell sein wie MongoDB – auch wenn der Vergleich etwas “hinkt” ...

Auf Amazon einkaufen & unterstützen

Facebook