Designing Data-Intensive Applications, ehrlich rezensiert
- #book review
- #data-engineering
- #distributed systems
- #Databases
- #System Design
- #Software Engineering
- #software development
- #Machine Learning
- #Devops
Jeder Engineer hat ein Buch, das man kauft, weil es immer wieder in den Empfehlungen anderer Leute auftaucht.
Fuer mich war das Designing Data-Intensive Applications von Martin Kleppmann. Ich erwartete einen zaehen Durchgang durch Datenbank-Interna. Bekommen habe ich etwas Selteneres: ein Buch, das praezise Namen fuer Probleme liefert, die ich in Produktion bereits halb erkannt hatte, und dann erklaert, warum sie entstehen.
Das hier ist keine Kapitel-fuer-Kapitel-Zusammenfassung. Kleppmann hat das Buch bereits geschrieben, und er macht es besser. Das hier ist, was bei mir haengen geblieben ist, gefiltert durch die Arbeit, die ich mache: Datenpipelines, ML-Systeme und die Glue-Architektur dazwischen.
Die Ideen, die ich jede Woche nutze
Beschreibe die Last, bevor du fuer Skalierung designst. “Skalierbarkeit” ist bedeutungslos, solange du die Lastparameter nicht benennen kannst: Reads versus Writes, Fan-out, Working Set Size, Cache Hit Rate, Datenvolumen, Request Rate und Latenzerwartungen.
Das klingt offensichtlich, und fast niemand macht es sorgfaeltig genug.
Meine erste Frage, wenn jemand sagt, eine Pipeline sei “langsam”, hat sich dadurch veraendert: langsam bei was genau? Oft beantwortet das Aufschreiben der Lastparameter die Frage, bevor ein Redesign beginnt.
Perzentile, nicht Durchschnitte. Durchschnittliche Antwortzeit ist eine bequeme Luege. Der p99-Wert ist dort, wo viele echte Beschwerden leben, weil der Nutzer mit den meisten Daten oft den Slow Path trifft.
Ich greife heute standardmaessig zu Perzentilen. Das gilt fuer Latenz-Dashboards, aber auch fuer Modell-Inferenzzeiten, Batch-Job-Straggler, Queue-Verarbeitung und Feature-Pipeline-Freshness.
Storage Engines erklaeren die Persoenlichkeit einer Datenbank. Das Kapitel ueber LSM-Trees und B-Trees ist das, das ich am haeufigsten empfehle.
Wenn du verstehst, dass PostgreSQL Seiten in place aktualisiert, waehrend Cassandra schreibt und spaeter kompaktiert, liest sich eine ganze Klasse von Vendor-Dokumentation weniger magisch. Du kannst vor dem Benchmark abschaetzen, welche Operationen wahrscheinlich billig sind, und bist nicht ueberrascht, wenn write-optimierte Systeme zur Lesezeit bezahlen lassen.
Schema-Evolution ist ein Deployment-Problem. Forward- und Backward-Kompatibilitaet machen Rolling Deploys moeglich: neuer Code liest alte Daten, und alter Code ueberlebt neue Daten.
Wer schon einmal einen Consumer mit “nur einem neuen Feld” gebrochen hat, kennt diesen Schmerz. Das Encoding-Kapitel ist die beste Begruendung, die ich fuer die Zeremonie von Avro oder Protobuf gelesen habe, statt JSON ueber die Wand zu werfen und zu hoffen.
Replication Lag ist eine Bug-Klasse, kein Edge Case. Wenn ein Nutzer etwas speichert, die Seite aktualisiert und die Aenderung verschwinden sieht, hast du Read-after-Write-Inkonsistenz getroffen.
Vor diesem Buch haette ich das als mysterioesen Einzelfall behandelt. Jetzt erkenne ich die Familie: stale reads, monotonic-read violations, causality violations und die kleinen UX-Entscheidungen, die sie verstecken oder sichtbar machen.
Der groesste Teil meiner Arbeit ist derived data. Feature Tables, Embeddings, Search Indexes, Caches und aggregierte Dashboards sind keine Systems of Record. Sie sind Views, die aus einer upstream Wahrheit abgeleitet werden, und sie sollten wiederaufbaubar sein.
Die Chunk-Embed-Index-Pipeline in meinem MkDocs-RAG-Projekt ist ein klassisches Derived-Data-System. Sobald man es so sieht, werden die Designprioritaeten klar:
- Die Quelle immutable oder versioniert halten.
- Jede Transformation idempotent machen.
- Lineage zwischen Quellrecords und abgeleiteten Outputs verfolgen.
- “Kann ich das von Grund auf neu verarbeiten?” als harte Anforderung behandeln.
Was man ueberfliegen kann
Das MapReduce-Material ist heute groesstenteils eine Geschichtsstunde. Es lohnt sich fuer die Join-Algorithmen, die das Framework ueberlebt haben, aber die meisten Engineers schreiben keine MapReduce-Jobs mehr direkt.
Die Byzantine-Fault-Abschnitte kann man ueberspringen, ausser man arbeitet an Peer-to-Peer-Systemen, Blockchain-Infrastruktur oder aehnlichen adversarial Environments.
Das Transaktionskapitel ist stark, geht aber tiefer in Isolation-Level-Anomalien, als viele Application Engineers im Alltag mit Managed Databases brauchen. Ich wuerde es trotzdem lesen, nur langsam und mit einem realen System im Kopf.
Was gut gealtert ist
Das Schlusskapitel ueber das Unbundling von Datenbanken ist in die andere Richtung gealtert als das MapReduce-Material. Es liest sich wie eine Vorhersage des modernen Data Stacks, bevor dieser seine heutige Form hatte.
Spezialisierte Storage Engines, log-zentrierte Integration, Stream Processors, die Systeme verbinden, und verschiedene derived views fuer verschiedene Access Patterns: Das beschreibt ziemlich gut, was viele Teams heute betreiben.
Deshalb bleibt das Buch nuetzlich. Es haengt nicht an einem einzelnen Vendor oder Framework. Es gibt dir das Vokabular unter den Tools.
Der ehrliche Teil
Ich nutze Managed Services, wie fast alle.
Ich habe nie einen leaderless Dynamo-style Cluster im Ernst betrieben oder eine Raft-Implementation um 3 Uhr morgens debuggt. Ueber Consensus zu lesen ist nicht dasselbe wie dafuer Pager-Dienst zu haben. Manche Teile von Part 2 bleiben fuer mich theoretisch, bis sie es ploetzlich nicht mehr sind.
Genau darin liegt der Wert.
Der Managed Service macht diese Dinge fuer mich, und das Buch sagt mir, welche Fragen ich stellen muss:
- Was passiert beim Failover?
- Welche Replication Guarantees gibt es?
- Ist dieser Timestamp wirklich monoton?
- Welches Consistency Model sieht die Anwendung?
- Was passiert, wenn ein Consumer zurueckfaellt?
- Kann ich diese derived view aus der Quelle neu aufbauen?
Das Wissen, dass diese Mechanik existiert und grob wie sie fehlschlaegt, ist der Unterschied zwischen Vendor-Dokumentation lesen und ihr nur glauben.
Warum es fuer ML- und Datenarbeit wichtig ist
Das Buch wird oft als Backend- oder Distributed-Systems-Buch beschrieben. Das stimmt, aber es ist genauso relevant fuer Data und ML Engineering.
Moderne ML-Systeme sind voll von datenintensiven Problemen:
- Trainingsdaten werden aus operativen Systemen abgeleitet.
- Feature Stores brauchen Freshness und Reproduzierbarkeit.
- Batch- und Streaming-Pipelines brauchen klare Konsistenzannahmen.
- Embedding-Indexes muessen rebuildbar und versionierbar sein.
- Modelloutputs werden oft Inputs fuer Downstream-Workflows.
- Analytics-Tabellen muessen Business-Bedeutung ueber Schema-Aenderungen hinweg erhalten.
Wenn deine Arbeit Datenpipelines oder produktives ML beruehrt, gibt dir das Buch ein staerkeres mentales Modell fuer die Systeme rund um das Modell.
Sollte man es lesen?
Ja, aber mit Strategie.
Lies Part 1 sorgfaeltig. Er bezahlt das ganze Buch.
Lies Part 2 langsam, idealerweise mit einem realen System im Kopf. Nicht unter Deadline-Druck.
Lies Part 3 fuer die Sichtweise. Dort verbindet sich das Buch am direktesten mit modernen Datenplattformen, ML-Pipelines, Suchsystemen und derived data.
Dann stell es ins Regal, wo du es erreichen kannst. Es ist ein Referenzbuch im Gewand eines Lehrbuchs, und der Nutzen waechst jedes Mal, wenn ein Produktionsproblem dich zu einem Kapitel zurueckschickt, das du schon fuer erledigt gehalten hast.
Referenz
Kleppmann, M. (2017). Designing Data-Intensive Applications. O’Reilly Media.
Portfolio-Seite: Designing Data-Intensive Applications, Honestly Reviewed