Azure Übersicht Teil 3: Cosmos DB
Der 2. Teil dieser Blog Serie hat die Möglichkeiten gezeigt, wie strukturierte Daten gespeichert werden.
Dieser Teil beschreibt die vielfältigen Möglichkeiten der Azure Cosmos DB (früher DocumentDB genannt).
Cosmos DB ist ein global verteilter, multi-model Datenbank Service, insbesondere für NoSQL Daten. Grosse Datenmengen (Big Data) lassen sich nicht in SQL Datenbanken verwalten, diese skalieren zu schlecht. Cosmos DB speichert Items in Containern (vergleichbar mit Tabellen) und gruppiert diese in “Datenbanken”. Eine Datenbank innerhalb einer Cosmos DB verhält sich wie ein Namespace.
Cosmos DB Paradigmen
Folgende Paradigmen werden unterstützt:
- Table API: Speichert Items in einer Table. Daten aus dem Table Storage lassen sich einfach in die Cosmos DB übertragen.
- SQL: Ein JSON-freundlicher SQL Dialekt erzeugt, aktualisiert und löscht Items und Container.
- MongoDB: speichert Dokumente in Collections
- Gremlin: für Graphdatenbanken, z.B. Speichern von Organisationsstrukturen. Speichert Graphen als Nodes und Edges.
- Cassandra: Interaktion mit der Datenbank mit der Cassandra Query Language (CQL). Ist ein Table Row Storage.
Die verschiedenen Paradigmen vereinfachen die Migration bestehender Datenbanken in die Cosmos DB. Der Entwickler wählt das Modell beim Anlegen der Cosmos DB und kann es später nicht mehr ändern.
Relationale Datenbanken zeichnen sich durch eine strenge ACID-Semantik aus und garantieren so jederzeit einen konsistenten Datenzustand. Dafür erleiden sie Einschränkungen bezüglich Parallelität, Latenz und Verfügbarkeit. Die hohen Konsistenzanforderungen sind nicht für jede Art von Applikation gefordert. Die bekannten Social Media Plattformen oder auch Suchmaschinen sind gute Beispiele, wo Konsistenz kein Kriterium ist. Dokumentenorientierte Datenbanken passen zudem hervorragend zu den objektorientieren Ansätzen in der Programmierung. Die Herstellung komplexer Beziehungen in relationalen Daten über Joins kann sehr teuer werden, da die Daten physikalisch nicht beieinander liegen. So ist es z.B. effizienter, alle Daten zu einem Mitarbeiter in einem einzigen JSON Dokument hierarchisch abzulegen, als sie über viele Tabellen zu verteilen. Beziehungen werden als “First-class Citizens” in der Datenbank abgelegt und auch Objekthierarchien sind einfach abzubilden.
Eine Cosmos DB anlegen
Nachdem man in Azure eine Cosmos DB angelegt hat, erzeugt man zunächst einen Container. Ein Container braucht einen Partition Key zur Strukturierung der Daten (z.B. /address/zipCode). Zudem definiert man einen Throughput in Request Units (RU) pro Sekunde, der die Performance der Datenbank steuert.
Cosmos DB verteilt die Daten aufgrund des Partition Key automatisch auf verschiedene physische Partitionen und kann so gut skalieren. Die richtige Wahl des Partition Key ist also wichtig, er soll die Daten möglichst gleichmässig verteilen, wie wir im folgenden sehen.
Partitionierung der Daten
Ein zentrales Element des Datenbankdesigns von NoSQL Datenbanken ist die Partitionierung. Wir unterschieden zwischen logischen und physischen Partitionen.
- Eine logische Partition ist ein Set von Items in einem Container mit dem gleichen Partition Key. Ein Container enthält so viele logische Partitionen wie nötig, aber deren Grösse ist auf 20 GB limitiert.
- Eine oder mehrere logische Partitionen liegen in einer physischen Partition. Eine physische Partition enthält zudem mehrere Kopien der Daten, Replica Set genannt. All dies wird von Cosmos DB verwaltet. Die vorhandenen RU’s werden gleichmässig über die physischen Partitionen verteilt. Wenn wir z.B. 20’000 RU’s für 2 phys. Partitionen haben und sich 95% der Daten in der einen Partition befinden, können wir faktisch nur gut 10’000 RU’s nutzen.
Aus diesem Grund ist die Wahl eines geeigneten Partition Key essentiell, weil dieser eine Anfrage zur korrekten Partition leitet. Es muss ein Wert sein, der sich für ein Item nie ändert, und soll viele unterschiedliche und gleich verteilte Werte haben. Zudem sollen Cross-Partition Abfragen minimiert werden. Cosmos DB verwendet einen Hash-Code für den Partition Key. Der Partition Key muss beim Anlegen eines Containers definiert werden. Gute Kandidaten sind Properties, die häufig als Filterparameter in Abfragen erscheinen. Geeignete Partition Keys sind z.B. TenantId, ZipCode, etc.
Konsistenzlevels
Für bessere Verfügbarkeit und geringere Latenz repliziert Cosmos DB seine Daten auf Wunsch rund um den Globus. Ein Update benötigt deshalb eine gewisse Zeit, bis die Daten auf alle Knoten verteilt sind. Während dieser Zeit sind die Daten nicht überall konsistent. Der Konsistenzlevel steuert, wie sich eine Datenbank in solchen Fällen verhalten soll.
Cosmos DB kennt 5 verschiedene Konsistenzlevels
- Eventual: höchste Verfügbarkeit und geringste Latenz. Inkosistenz ist akzeptiert, aber es dauert eine Weile, bis geänderte Daten zu allen Nodes repliziert sind. Es ist auch nicht garantiert, dass die eigenen Writes bereits gelesen werden.
- Consistent prefix: Updates liefern einen Prefix aller Updates. Dies garantiert, dass beim Lesen nie ein ausserordentliches Write gesehen wird. Die Updates werden in der korrekten Reihenfolge gelesen.
- Session: Konsistent für den eigenen Client
- Bounded staleness: Konsistent für Clients der gleichen Region. Eine Lese Operationen hat eine maximale Verzögerung (Anzahl Versionen oder Zeit).
- Strong: Garantie, das Leseoperationen stets die letzten Daten liefern. Ein Benutzer sieht immer die zuletzt geschriebenen Daten. Höhere Latenzen
Konsistenzlevel greifen entweder auf Account Level (Default Wert) oder sind Request-spezifisch. Strong und Bounded Staleness erfordern die doppelte Menge an Request Units (RU) für einen Request.
Request Units
Die Kosten für eine Cosmos DB sind bestimmt durch den gewünschten Datendurchsatz, gemessen in Request Units (RU). Die Kosten einer Leseoperation von einem kByte Daten entspricht 1 RU. Der Durchsatz lässt sich auf Datenbank oder Container-Level einstellen. Ein Minimum von 10 RU pro GByte Speicher ist erforderlich, das Minimum beträgt 400 RU’s/s. Wenn die eingestellte Anzahl RU aufgebraucht ist, schlagen nachfolgende Operationen fehl. Deshalb macht es Sinn, dafür Autoscaling mit einem Maximalwert einzustellen. Der minimale Durchsatz beträgt 10% des Maximums.
Eine neue Option ist Cosmos DB Serverless: Dabei zahlt man nur für die verbrauchten RU’s und den Speicher. Das ist ideal für On/Off Workloads und Entwicklungsdatenbanken. Im Moment ist diese Einstellung nur für das SQL API verfügbar. Wichtig ist eine Strategie für gleichmässig verteilte Partitionen.
Programmierung der Cosmos DB
Cosmos DB unterstützt auch Stored Procedures, Triggers und benutzerdefinierte Funktionen. Als Programmiersprache gibt es nur JavaScript. Eine Stored Procedure kann nur auf Daten innerhalb desselben Partition Key zugreifen. Dieser muss der Prozedur bekannt sein, bevor sie ausgeführt wird.
Triggers können vor (pre) oder nach (post) der Datenbankaktion laufen. Pre Trigger machen Datentransformationen oder Validierungen, während Post Trigger Aggregationen oder Änderungsnotifikationen erledigen.
In Teil 4 dieser Blogserie werden die verschiedenen Technologien zur Analyse von Daten betrachtet.