CQRS ist ein Architekturpattern, das in modernen Backend-Systemen immer häufiger eingesetzt wird, insbesondere dort, wo Leistung und Skalierbarkeit entscheidend sind. Kurz gesagt, CQRS trennt Lese- und Schreiboperationen von Daten, anstatt sie - wie im klassischen CRUD-Ansatz - gleichermaßen zu behandeln.
Auf den ersten Blick wirkt das wie eine unnötige Komplexität: Warum etwas trennen, das auch so funktioniert? Doch in der Praxis haben Lese- und Schreibzugriffe oft ganz unterschiedliche Anforderungen. Ein System erhält beispielsweise tausende Leseanfragen, aber nur wenige Schreibvorgänge. Oder die Logik beim Schreiben ist so komplex, dass sie schnelles Lesen ausbremst.
Hier setzt CQRS an: Es erlaubt, jeden Teil des Systems gezielt zu optimieren - Schreiben für komplexe Logik, Lesen für Geschwindigkeit und Benutzerfreundlichkeit.
CQRS einfach erklärt
CQRS (Command Query Responsibility Segregation) teilt ein System in zwei Bereiche:
- Command - für Änderungen an den Daten
- Query - für das Auslesen von Daten
Die Hauptidee ist, dass Lese- und Schreiboperationen nicht das gleiche Datenmodell verwenden sollen.
In der klassischen CRUD-Architektur arbeitet alles über eine einzige Schicht: Ein Modell ist zuständig für Erstellen, Aktualisieren und Auslesen von Daten. Das ist praktisch, stößt aber mit wachsender Komplexität an Grenzen.
CQRS geht einen anderen Weg:
- Commands ändern nur den Status, liefern aber keine Daten zurück
- Queries lesen nur Daten, verändern aber nichts
Beispiele:
- Bestellung anlegen - ein Command
- Liste der Bestellungen abrufen - eine Query
Diese Trennung ermöglicht:
- einfachere Business-Logik für Schreibvorgänge
- schnelleres Auslesen der Daten
- flexible Skalierung des Systems
Das Resultat: Es entstehen zwei Modelle:
- Write Model - für Schreiboperationen
- Read Model - für Leseoperationen
Beide können nach Anforderung ganz unterschiedlich aufgebaut sein.
Wie funktioniert CQRS?
Im Kern von CQRS steht die Idee, dass Lese- und Schreibzugriffe sowohl logisch als auch architektonisch getrennt werden. Das bedeutet: Das System behandelt Commands und Queries unterschiedlich.
Commands - Daten ändern
Commands steuern alle Veränderungen am Systemzustand, zum Beispiel:
- Nutzer anlegen
- Bestellung erfassen
- Profil aktualisieren
- Daten löschen
Ein Command signalisiert immer die Absicht, etwas zu ändern. Typische Merkmale:
- liefert keine oder nur minimale Rückgabe (z. B. Status)
- wird durch die Business-Logik geführt
- löst Validierungen und Prüfungen aus
Beispiel: CreateOrderCommand für das Anlegen einer Bestellung.
Wichtig: Ein Command dient nie dem Auslesen von Daten - sondern nur der Statusänderung.
Queries - Daten auslesen
Queries sind reine Leseoperationen, die:
- keine Daten verändern
- Ergebnisse wie Listen, Objekte oder Statistiken zurückgeben
- auf maximale Geschwindigkeit optimiert sind
Beispiel: GetOrdersQuery - liefert eine Liste von Bestellungen.
Im CQRS können Queries auf ein speziell optimiertes Datenmodell zugreifen, z.B.:
- denormalisierte Datenbank
- Cache
- eigene Read-Replica
Trennung der Modelle: Write Model und Read Model
Das Herzstück von CQRS ist die Existenz von zwei Modellen:
- Write Model: Für Commands, enthält komplexe Business-Logik, ist normalisiert und auf Datenkonsistenz ausgelegt.
- Read Model: Für Queries, meist vereinfacht, kann denormalisiert und auf schnelle Abfragen optimiert sein.
Beispiel Online-Shop:
- Write Model speichert Bestellungen, Produkte und Nutzer normalisiert.
- Read Model stellt fertige Ansichten bereit, z.B. "Bestellungen mit Nutzername und Gesamtsumme".
Datenfluss im System
- Der Nutzer sendet einen Command (z. B. Bestellung anlegen).
- Das System verarbeitet den Command und speichert die Änderung.
- Das Read Model wird (oft asynchron) aktualisiert.
- Die nächste Abfrage liefert bereits die neuen Daten.
Durch die Asynchronität kann es vorkommen, dass das Read Model nicht sofort aktualisiert ist - das nennt sich eventual consistency (Konsistenz mit Verzögerung).
Dieser Ansatz bietet Flexibilität, verlangt aber nach einer durchdachten Architektur.
CQRS vs. CRUD - Wo liegt der Unterschied?
Um den Wert von CQRS zu verstehen, lohnt sich der Vergleich mit dem klassischen CRUD-Ansatz (Create, Read, Update, Delete), der in den meisten Anwendungen Standard ist.
Wie funktioniert CRUD?
Bei CRUD gibt es ein einheitliches Datenmodell für alle Operationen:
- Erstellen
- Lesen
- Aktualisieren
- Löschen
Typisch:
- eine Datenbank
- eine Modellstruktur
- eine Logikschicht
Beispiel: Die Tabelle Users wird für Lesen, Schreiben und Aktualisieren gleichermaßen genutzt - besonders praktisch zu Projektbeginn.
Grenzen von CRUD
- Komplexe Business-Logik: Das Modell wird mit Validierungen, Regeln und Beziehungen überladen.
- Performance-Probleme: Dieselben Datenmodelle werden für Lesen und Schreiben genutzt, obwohl die Anforderungen unterschiedlich sind.
- Skalierungsschwierigkeiten: Lesen und Schreiben lassen sich nicht getrennt optimieren.
- Unhandliche Abfragen: Komplizierte JOINs sind nötig, um Daten auszulesen.
Wie CQRS diese Probleme löst
CQRS trennt die Verantwortlichkeiten:
- Schreiben über Commands und Write Model
- Lesen über Queries und Read Model
Das bringt Vorteile wie:
- unterschiedliche Datenbanken können genutzt werden
- Lesen wird schneller (Daten sind vorab aggregiert und vorbereitet)
- Schreiben bleibt sauber und logisch
- die Skalierung wird einfacher
Beispiel:
- Bestellung speichern: komplex mit Prüfungen
- Bestellungen abfragen: schnelle, bereits aggregierte Ergebnisse
Wann wird der Unterschied wichtig?
- In hochbelasteten Systemen
- Bei Anwendungen mit vielen Lesevorgängen (Analytics, Dashboards)
- In komplexen Business-Systemen (Finanzen, E-Commerce)
Zusammengefasst:
- CRUD - schnell einzuführen, einfach zu warten am Anfang
- CQRS - anspruchsvoller, aber besser skalierbar und für Wachstum geeignet
CQRS ersetzt CRUD nicht komplett - es ist der nächste Evolutionsschritt, wenn das einfache Modell an seine Grenzen stößt.
CQRS-Architektur in der Praxis
Wird CQRS praktisch angewendet, beeinflusst es die gesamte Systemarchitektur - nicht nur einzelne Methoden, sondern auch Speicherung, Verarbeitung und Datenübertragung.
Datenbanken trennen
Im einfachsten Fall nutzt CQRS eine Datenbank, aber verschiedene Modelle. Fortgeschrittene Szenarien trennen physisch:
- Datenbank für Schreiben (write database)
- Datenbank für Lesen (read database)
Dadurch:
- Schreiben kann für Transaktionen und Integrität optimiert werden
- Lesen für Geschwindigkeit und Skalierung
Beispiel:
- Write DB: PostgreSQL
- Read DB: Elasticsearch oder Redis
Unterschiedliche Datenmodelle
Im CQRS können sich Modelle für Lesen und Schreiben stark unterscheiden:
- Write Model: normalisierte Tabellen, strikte Struktur, Business-Logik
- Read Model: aggregierte Daten, minimale Beziehungen, sofort verwendbare Ansichten
Beispiel: Anstatt komplexer JOINs hält das Read Model bereits fertige Resultate bereit:
- Nutzername
- Bestellungslisten
- Gesamtsumme
Das beschleunigt Abfragen enorm.
Asynchronität und Eventual Consistency
Ein Schlüsselfaktor von CQRS: Die Synchronisierung zwischen Write und Read Model erfolgt oftmals verzögert.
- Ein Command ändert das Write Model
- Das System erzeugt ein Event
- Das Read Model wird (meist asynchron) aktualisiert
Dadurch entsteht eventual consistency: Die Daten stimmen mit Verzögerung überein. Wichtig:
- Nutzer sehen ggf. kurzfristig veraltete Daten
- Das System muss auf Verzögerungen vorbereitet sein
Beispiel einer Systemarchitektur
- API nimmt Commands und Queries entgegen
- Commands werden von einem eigenen Handler verarbeitet
- Queries gehen direkt an die Read Model
- Events aktualisieren das Read Model
Komplexere Systeme setzen zusätzlich ein:
- Message Broker (Kafka, RabbitMQ)
- getrennte Lese- und Schreibservices
- Caching
CQRS muss nicht sofort komplett eingeführt werden - oft reicht eine teilweise Trennung auf Logik-Ebene ohne eigene Datenbanken.
CQRS und Event Sourcing: Wie hängen sie zusammen?
CQRS wird oft im Zusammenhang mit Event Sourcing genannt - aus gutem Grund. Beide Patterns ergänzen sich und kommen in komplexen Systemen häufig gemeinsam zum Einsatz.
Was ist Event Sourcing?
Klassische Systeme speichern den aktuellen Zustand, z.B. "Kontostand: 1000".
Event Sourcing speichert nicht den Zustand, sondern alle Ereignisse, die dazu geführt haben:
- Nutzer zahlt 500 ein
- Nutzer bezahlt Bestellung mit 200
- Nutzer erhält 700 Bonus
Der aktuelle Stand wird aus allen Ereignissen berechnet.
Wie arbeitet CQRS mit Event Sourcing?
- CQRS trennt Commands (ändern Daten) und Queries (lesen Daten)
- Event Sourcing speichert die Änderungen als Ereignisse
- Jeder Command erzeugt ein Event, das im Log gespeichert wird
- Ein Command gelangt ins System
- Ein Event (z.B. OrderCreated) wird erzeugt
- Das Event wird gespeichert
- Das Read Model wird auf Basis der Events aktualisiert
Warum werden CQRS und Event Sourcing oft kombiniert?
- Veränderungshistorie: Der komplette Systemverlauf ist rekonstruierbar
- Debugging & Auditing: Jede Aktion ist nachvollziehbar
- Flexible Read Models: Read Models können aus Events beliebig neu aufgebaut werden
- Skalierbarkeit: Events lassen sich leicht an andere Services weitergeben
Wann ist diese Kombination sinnvoll?
- Wenn die Änderungshistorie wichtig ist (Finanzen, Logistik)
- Bei komplexen, verteilten Systemen
- Wenn hohe Skalierbarkeit gefordert ist
Achtung: Diese Architektur ist komplex und erfordert Erfahrung.
Für viele Projekte genügt CQRS allein - Event Sourcing ist vor allem in Spezialfällen relevant.
Vor- und Nachteile von CQRS
CQRS eröffnet viele Möglichkeiten, bringt aber auch neue Herausforderungen. Ein Überblick:
Vorteile
- Skalierbarkeit: Lese- und Schreiboperationen lassen sich unabhängig voneinander skalieren (z.B. mehr Read-Replicas ohne Auswirkungen auf das Write Model)
- Hohe Performance: Das Read Model kann für spezifische Abfragen optimiert werden (Cache, Denormalisierung, fertige Views) - ideal für Systeme mit vielen Lesezugriffen
- Architektonische Flexibilität: Verschiedene Technologien für Lesen und Schreiben (z.B. SQL für Schreiben, NoSQL für Lesen) lassen sich kombinieren
- Saubere Business-Logik: Das Write Model ist frei von Darstellungslogik und konzentriert sich auf die Korrektheit der Änderungen
Nachteile
- Komplexe Einführung: Mehr Komponenten (Commands, Handler, Events, Modelle) erhöhen die Einstiegshürde
- Eventual Consistency: Daten werden nicht sofort synchronisiert - Nutzer sehen ggf. kurzfristig alte Daten
- Schwierige Fehlersuche: Durch Asynchronität ist die Ursachenanalyse fehlerhafter Daten schwieriger
- Überdimensioniert für kleine Projekte: Bei überschaubaren Systemen bringt CQRS mehr Komplexität als Nutzen
CQRS ist kein Allheilmittel - es bietet Vorteile nur unter bestimmten Bedingungen.
Wann ist CQRS sinnvoll?
CQRS ist kein Muss für jedes Projekt. Es entfaltet seine Stärke nur bei bestimmten Anforderungen:
Hochlastsysteme
Bei vielen Leseoperationen (z.B. Dashboards, Analyseplattformen, Marktplätze, soziale Netzwerke) kann CQRS das Lesen auslagern und für Geschwindigkeit optimieren - das reduziert die Last auf das Hauptsystem und verbessert die Antwortzeiten.
Komplexe Business-Logik
Enthalten Schreiboperationen zahlreiche Prüfungen, Regeln und Abhängigkeiten, vereinfacht CQRS deren Isolierung und macht sie verständlicher.
Unterschiedliche Anforderungen an Lesen und Schreiben
Typisch:
- Schreiben erfordert strenge Konsistenz
- Lesen muss schnell und flexibel sein
CQRS macht beides möglich: sichere, korrekte Speicherung und schnelle, benutzerfreundliche Abfragen.
Verteilte Systeme und Microservices
CQRS passt hervorragend in moderne Systemlandschaften. Mehr dazu findest du in unserem Beitrag "Microservices vs. Monolith: Architekturwahl für IT-Teams 2025".
In solchen Systemen:
- können Services getrennt für Lesen und Schreiben verantwortlich sein
- werden Daten per Events weitergegeben
- ist die Skalierung einzelner Bereiche einfach möglich
Wo CQRS nicht gebraucht wird
- Kleine Projekte
- Einfache Logik
- Geringe Last
- Begrenzte Teamressourcen
Hier würde CQRS die Entwicklung unnötig erschweren.
Faustregel: Wenn CRUD bei Komplexität oder Last an Grenzen stößt, ist CQRS eine Überlegung wert.
Wie führt man CQRS ein?
Der Umstieg auf CQRS bedeutet selten einen Komplettumbau. Meist wird schrittweise gestartet - dort, wo es am meisten bringt.
Schrittweise Einführung
Am sinnvollsten ist es, nicht direkt alles umzubauen. Beginne mit:
- Trennung von Command- und Query-Logik
- eigenen Handlern
- optimiertem Lesen durch spezielle DTOs oder Views
So bringt CQRS schon erste Vorteile, auch ohne große Infrastrukturänderungen.
Logik trennen - ohne Datenbankumbau
CQRS lässt sich zunächst auf Code-Ebene einführen:
- Commands als eigene Klassen/Methoden
- Queries als eigene Services
Beispiele:
- CreateOrderCommandHandler
- GetOrdersQueryHandler
Das hilft beim Strukturieren, Trennen der Verantwortlichkeiten und erleichtert die Wartung.
Architektur bei wachsendem System ausbauen
Mit zunehmender Größe kann man nach und nach ergänzen:
- eigene Read Models
- Caching
- asynchrone Event-Verarbeitung
- Message Broker (Kafka, RabbitMQ)
Wichtig: Nur ausbauen, wenn echte Notwendigkeit besteht.
Typische Fehler bei der Einführung
- Zu frühe Komplexität: CQRS wird vorschnell eingeführt, obwohl das System noch einfach ist.
- Eventual Consistency ignoriert: Verzögerungen bei der Datenaktualisierung werden nicht beachtet - das führt zu Fehlern.
- Übertriebene Architektur: Event Sourcing und Broker werden ohne echten Bedarf integriert.
- Unklare Trennung: Command und Query werden nicht sauber getrennt - der Sinn von CQRS geht verloren.
CQRS ist ein evolutionärer Schritt, kein Startpunkt - seine Stärke liegt darin, dass es Schritt für Schritt eingeführt werden kann.
Fazit
CQRS ist ein Architekturpattern, das Lese- und Schreibzugriffe trennt und dadurch mehr Performance, Flexibilität und Skalierbarkeit ermöglicht. Besonders profitabel ist es in Projekten mit hoher Last und komplexer Logik, wo der klassische CRUD-Ansatz an seine Grenzen stößt.
Doch CQRS ist kein Patentrezept: In einfachen Systemen kann es die Entwicklung verkomplizieren und Fehler fördern. Daher sollte CQRS gezielt eingesetzt werden - wenn echte Probleme zu lösen sind.
Zusammengefasst:
- Kleines Projekt? → Bleib bei CRUD
- Wachsende Last und Komplexität? → CQRS prüfen
Pragmatisch ist, CQRS schrittweise einzuführen - dort, wo es echten Mehrwert bringt.