Kommentar von Constantin Gonzalez und Florian Mair, Amazon Web Services So gelingt eine skalierbare Datenarchitektur mit CQRS

Autor / Redakteur: Constantin Gonzalez und Florian Mair * / Nico Litzel

Wenn mehrere Applikationen eine Datenbank verwenden, die nicht die jeweils applikationsspezifischen Anforderungen erfüllen kann, hilft das Command-Query-Responsibility-Segregation-Architekturmuster (CQRS) weiter. Es trennt schreibende und lesende Zugriffe, sodass diese voneinander getrennt und auf verschiedenen Datenbanken ausgeführt werden.

Firmen zum Thema

CQRS basiert darauf, Operationen welche den Datenzustand verändern separat von den lesenden Operationen zu behandeln. Die Separierung der zwei Zugriffsmuster erlaubt es, die jeweiligen Anforderungen an Skalierung, Latenz oder Schema, mit einer für den Einsatzzweck optimalen Datenbank umzusetzen.
CQRS basiert darauf, Operationen welche den Datenzustand verändern separat von den lesenden Operationen zu behandeln. Die Separierung der zwei Zugriffsmuster erlaubt es, die jeweiligen Anforderungen an Skalierung, Latenz oder Schema, mit einer für den Einsatzzweck optimalen Datenbank umzusetzen.
(Bild: © Golden Sikorka – stock.adobe.com)

Wenn Applikationen mit einer Datenbank interagieren, verwenden sie meist die Standard-CRUD-Operationen (Create, Read, Update, Delete). Dabei kommt es relativ häufig vor, dass Schreibvorgänge andere Anforderungen (z. b. Skalierung, Schema) als Lesevorgänge haben. Das führt dazu, dass mehrere Applikationen eine Datenbank verwenden, die nicht die jeweils applikationsspezifischen Anforderungen erfüllen kann. Beispielsweise wird bei einer E-Commerce-Applikation oft eine relationale Datenbank eingesetzt, um Bestellungen zu speichern. Dadurch können bei lesendem Zugriff komplexe Queries über mehrere Tabellen hinweg ausgeführt werden. Dagegen kommen SQL-Datenbanken aufgrund ihrer Architektur bei schreibenden Zugriffen schnell an ihre Grenzen.

Das Command-Query-Responsibility-Segregation-Architekturmuster (CQRS) schafft bei solchen Problemen Abhilfe. Dieses Architekturpattern trennt schreibende und lesende Zugriffe, sodass diese voneinander getrennt und auf verschiedenen Datenbanken ausgeführt werden.

Architekturpattern: Command Query Responsibility Segregation (CQRS)

Das Architekturpattern CQRS basiert darauf, Operationen welche den Datenzustand verändern (Create, Update), separat von den lesenden Operationen zu behandeln. Die Separierung der zwei Zugriffsmuster erlaubt es, die jeweiligen Anforderungen an Skalierung, Latenz oder Schema, mit einer für den Einsatzzweck optimalen Datenbank umzusetzen. Damit beide Datenspeicher denselben Datenstand vorweisen, muss dieser in einem für die Applikation unsichtbaren Hintergrundprozess repliziert werden.

Darstellung des CQRS-Achitekturpatterns
Darstellung des CQRS-Achitekturpatterns
(Bild: AWS)

Durch die Notwendigkeit der Datenreplikation zwischen der Schreib- und Lesedatenbank und der sich daraus ergebenden Verzögerung ist CQRS am besten für die Applikationen geeignet, die mit weniger strikten Anforderungen an die Konsistenz zwischen Lese- und Schreibvorgängen (Eventual Consistency) umgehen können.

Die Separierung von Schreib- und Lesezugriffen auf zwei verschiedene Datenbanken lässt sich gut mit anderen Architekturmustern wie zum Beispiel Microservices oder Event Sourcing kombinieren. Bei der Verwendung von Microservices werden komplexe Prozesse in unabhängige Services aufgeteilt, welche über Schnittstellen kommunizieren. Bei der Verwendung von CQRS kann für Schreib- und Lesezugriff jeweils ein separater Microservice erstellt werden, allerdings ist dies nicht zwingend nötig, da die Separierung auch im Applikationscode erfolgen kann.

Doch wie integriert sich CQRS mit Event Sourcing? Beim Event Sourcing werden Datenänderungen nicht direkt in die Datenbank geschrieben, sondern als Ereignisse (Events) zu einem Eventlog (wie z. B. Apache Kafka) hinzugefügt. Dabei wird die Schreib-Datenbank durch das Eventlog ersetzt und Datenstände werden durch Event Handler in die Lese-Datenbank repliziert. Der Datenstand im Eventlog spiegelt dabei nicht nur den aktuellsten Datenstand wieder, sondern die komplette Historie eines Datensatzes. Dadurch kann nicht nur der letzte Datenstand in eine Lese-Datenbank repliziert werden, sondern auch ein Datenstand zu einem beliebigen Zeitpunkt.

Beispiel: Produktdatenbank Replikation von MySQL zu Elasticsearch mit Python

Elasticsearch ist ein verteiltes Such- und Analyse-Werkzeug für verschiedene Daten wie Text, Geo, unstrukturiert und strukturiert. Die verteilte Architektur von Elasticsearch erlaubt eine hohe Skalierbarkeit und Performance für große Datenmengen. SQL Datenbanken wie zum Beispiel MySQL sind im Vergleich zu Elasticsearch weniger für Anwendungsfälle wie z. B. Volltextsuche optimiert. Das liegt daran, dass in Elasticsearch Textdaten anders indexiert sind als eine SQL-Datenbank.

Als praktisches Beispiel kann hier eine Produktdatenbank dienen. Ein Online-Shop speichert deren Produktkatalog in einer MySQL-Datenbank. Das funktioniert problemlos, um neue Produkte einzufügen, zu aktualisieren, und zu löschen. Nun entscheidet sich das Unternehmen, eine Volltextsuche für Produkte einzuführen. Die MySQL Datenbank stößt hierbei an ihre Grenzen, da Kunden nicht nach der spezifischen Produkt-ID suchen, sondern nach Schlagworten wie z. B. „Grüner Schal für Damen“, welche nicht im Index der SQL-Datenbank abgebildet sind. In einem solchen Fall können mit einer CQRS-Architektur die Volltext-Suchanfragen an Elasticsearch geleitet werden. Dabei bleiben die Anfragen für das Ändern und Hinzufügen von Produkten weiterhin auf der MySQL-Datenbank.

Um die zwei Datenspeicher auf demselben Datenstand zu halten, stehen Werkzeuge in verschiedenen Programmiersprachen zur Verfügung. Im folgenden Beispiel wird python-mysql-replication verwendet.

Datenbank-Replikation mittels python-mysql-replication
Datenbank-Replikation mittels python-mysql-replication
(Bild: AWS)

Um diese Library verwenden zu können, muss auf der MySQL-Datenbank das Binary Log in der Konfigurationsdatei aktiviert werden. Dieser Log beinhaltet Events, die die Datenbank-Änderungen beschreiben. Beim Einfügen eines neuen Datensatzes in eine Tabelle mit 2 Spalten könnte ein Binary-Log-Eintrag folgendermaßen aussehen:

INSERT INTO `shop`.`produkte`SET@1 = 1 /* INT meta=0 nullable=0 */@2 = 'Grüner Schal für Damen' /* VARSTRING(20) meta=0 nullable=1 */......

Die mysql-replication library übernimmt das Konsumieren der Daten vom Binary Log und bereitet diese in ein Format auf, das von Elasticsearch weiterverarbeitet werden kann. Die aufbereiteten Daten können dann mittels der Elasticsearch-API in den Elasticsearch-Cluster übertragen werden.

Umsetzung auf AWS

Es gibt verschiedene Möglichkeiten, Datenbestände zu replizieren. Ein entscheidender Faktor hierbei sind die verwendeten Datenbank-Engines für Quell- und Zielsystem. Viele Datenbanken unterstützen eine Form von Change Data Capture (CDC), wo Änderungen an Daten nach an der Echtzeit erfasst und dann in das Zielsystem übertragen werden. Bei einer MySQL-Datenbank als Quellsystem kann das Binary Log verwendet werden, um Änderungen zu erfassen und diese in ein Zielsystem per Streaming zu übertragen.

Änderungen streamen mit dem AWS Database Migration Service (DMS)

Mit AWS DMS können Daten zwischen homogenen Datenbanken wie MySQL zu MySQL sowie heterogene Datenbankplattformen wie MySQL zu Amazon Elasticsearch Service übertragen werden. Mit diesem Service kann sowohl eine initiale Migration als auch eine kontinuierliche Datenreplikation mittels CDC vorgenommen werden. Beim Einsatz von DMS für CQRS-Zwecke werden meistens verschiedene Datenbankplattformen verwendet. Daher kann es nötig sein, dass Schema zu konvertieren. Dafür stellt AWS das AWS Schema Conversion Tool (SCT) zur Verfügung.

Datenreplikation mit AWS Database Migration Service
Datenreplikation mit AWS Database Migration Service
(Bild: AWS)

Materialized Views mit AWS Glue Elastic Views (in Vorschau)

AWS Glue Elastic Views steht seit 1.12.2020 in verschiedenen AWS-Regionen in den USA, Asia Pacific (Tokyo) und in Europa (Irland) zur Verfügung. Mit dieser neuen Funktion von AWS Glue ist es möglich, sog. Materialized Views zu erzeugen, ohne einen Code selber zu schreiben, da die Tabellendefinition mithilfe von SQL-Befehlen erfolgt. Da AWS Glue Elastic Views im Gegensatz zu DMS als „serverless“-Dienst konzipiert ist, entfällt bei der Verwendung die Verwaltung von einzelnen Servern. Das bedeutet auch, dass die Kapazität automatisch, je nach Datendurchsatz, skaliert wird. Derzeit werden Amazon DynamoDB, Amazon S3, Amazon Redshift und Amazon Elasticsearch Service unterstützt. Bald sollen auch Amazon RDS und Amazon Aurora unterstützt werden.

Datenreplikation mittels AWS Glue Elastic Views (in Vorschau)
Datenreplikation mittels AWS Glue Elastic Views (in Vorschau)
(Bild: AWS)

Fazit

Command Query Responsibility Segregation (CQRS) ist ein Architekturpattern um Schreib- und Lesevorgänge getrennt voneinander zu behandeln, damit der jeweils geeigneten Datenspeicher für das jeweilige Zugriffsmuster verwendet werden kann. Dadurch kann die Performance von Applikationen optimiert werden, allerdings können durch die nötige Replizierung und das Betreiben von zwei Datenspeichern auch zusätzliche Kosten entstehen. Um Applikationen zu optimieren, kann CQRS sowohl in On-premises-Rechenzentren als auch in der Cloud umgesetzt werden. Durch das Betreiben von CQRS in einer Cloud-Umgebung können verwaltete Datenbanksysteme, wie zum Beispiel Amazon RDS, verwendet werden, was den Management-Aufwand für Datenbanken reduziert. Des Weiteren stellt AWS mit AWS DMS und AWS Glue Elastic Views zwei vollständig verwaltete Services zur Verfügung, die für die Datenreplikation verwendet werden können.

* Constantin Gonzalez ist Principal Solutions Architect und Florian Mair Solutions Architect bei Amazon Web Services

(ID:47467158)