Warum Datenbanken und ihre Komplexität heute unnötig sind
(blog.redplanetlabs.com)- Die Ursache der Backend-Komplexität liegt weniger in Mängeln bestimmter Produkte, sondern darin, dass die von Datenbanken seit Langem aufrechterhaltene konzeptionelle Struktur das Application-Design weiterhin einschränkt
- Datenbanken verhalten sich wie global veränderbarer Zustand und bürden Entwicklerinnen und Entwicklern feste Datenmodelle, eingeschränkte Schemata sowie die Spannung zwischen Normalisierung und Denormalisierung auf
- Die vorgeschlagene Alternative kombiniert Event Sourcing und materialized views, trennt Quelldaten und Index-Views und behandelt Indizes nicht als Datenmodell, sondern als langlebige Datenstrukturen
- Rama von Red Planet Labs bündelt mit depots, ETL, PStates und query topologies Datenerfassung, -verarbeitung, -indizierung sowie Abfragen, Deployment und Monitoring in einer Plattform
- Beim Beispiel einer Mastodon-Neuimplementierung im Twitter-Maßstab wurde Rama mit 10k Zeilen und 9 Personenmonaten umgesetzt; zum Vergleich soll das entsprechende Twitter-Consumer-Produkt 1M Zeilen und rund 200 Personenjahre erfordert haben
Ausgangspunkt der Datenbank-Komplexität
- Im Fokus des Problems stehen nicht API, Betriebsprobleme oder willkürliche Beschränkungen einzelner Datenbankprodukte, sondern die bis heute fortbestehende kollektive konzeptionelle Struktur
- Erst wenn ein besserer Ansatz auftaucht, werden die Probleme des bisherigen Ansatzes klar sichtbar; als Alternative wird eine Kombination aus event sourcing und materialized views vorgeschlagen
Datenbanken als global veränderbarer Zustand
- Programmierer lernen, globale Variablen möglichst zu vermeiden, doch auch eine Datenbank ist im Kern global veränderbarer Zustand
- Datenbanken sind in mancher Hinsicht noch schwerer zu handhaben als gewöhnliche globale Variablen
- Interaktionen sind über mehrere Systeme verteilt, wodurch sich der Zustand schwer erschließen lässt
- Der Zustand ist dauerhaft, daher wird beschädigte Datenlage nicht automatisch repariert, selbst wenn ein Bug behoben wird
- Es kann schwierig sein, das genaue Ausmaß einer Beschädigung zu bestimmen oder vollständig zu korrigieren
- Auf ein Backup zurückzugehen oder Teile eines Backups zusammenzuführen, ist keine optimale Lösung
- Mit Event Sourcing und materialized views lassen sich Views aus dem Quell-Log neu berechnen, sodass sich beschädigter Indexzustand korrigieren lässt
Grenzen fester Datenmodelle
- Datenbanken sind um Datenmodelle wie key/value, document, relational, column-oriented oder graph herum entworfen
- Da ein einzelnes Datenmodell kaum alle Use Cases abdecken kann, setzen Unternehmen oft mehrere Datenbanken gemeinsam ein
- Die allgemeinere Index-Abstraktion ist nicht ein Datenmodell, sondern eine Datenstruktur
- Key/value: map
- Document: map of maps
- Relational: map of maps, secondary indexes sind zusätzliche maps
- Column-oriented: map of sorted maps
- Langlebige Datenstrukturen können auf der Festplatte gespeichert werden, sehr groß werden und auch verschachtelte Datenstrukturen ausdrücken
- Wenn Indizes als Kombinationen von Datenstrukturen beschrieben werden, lassen sich nicht nur bestehende Datenmodelle, sondern auch vielfältigere Indexformen erzeugen
- Wenn man statt das Anwendungs-Domänenmodell an die Datenbank anzupassen die Form des Speichers an das Domänenmodell anpassen kann, sinkt die grundlegende Komplexität
Die Spannung zwischen Normalisierung und Denormalisierung
- Nutzer relationaler Datenbanken stehen letztlich vor der Wahl zwischen Normalisierung und Denormalisierung
- Normalisierte Speicherung schafft eine klare Source of Truth und reduziert das Risiko von Inkonsistenzen, kann aber durch mehr Joins teurere Abfragen verursachen
- Wenn aus Performance-Gründen dieselben Informationen mehrfach gespeichert werden, können bei Bugs Dateninkonsistenzen entstehen
- Die RDBMS-Architektur legt Source of Truth und Indexspeicher für schnelle Abfragen im selben Datastore zusammen
- Die Lösung ist eine Struktur, die diese beiden Rollen trennt
- Ein Subsystem stellt die Source of Truth dar
- Ein anderes Subsystem materialisiert daraus beliebig viele Indexspeicher
- Wenn das zweite System Indizes aus den Quelldaten neu berechnen kann, lassen sich Inkonsistenzen korrigieren
Eingeschränkte Schemata und Domänenrepräsentation
- Datenbanken unterscheiden sich je nach Produkt stark in den Arten von Werten, die sie speichern können
- Manche Datenbanken erlauben nur blobs wie byte arrays
- Andere erlauben viele Typen wie Ganzzahlen, Fließkommazahlen, Strings und Datumswerte
- Es ist selten, verschachtelte Informationen innerhalb von Domänenobjekten so als erstklassige Repräsentation zu speichern, dass sie direkt abgefragt oder aggregiert werden können
- Weil sich Implementierungssprache der Datenbank und Anwendungssprache unterscheiden, ist Interoperabilität schwierig; Erweiterungen wie die protobuf extension für Postgres sind ebenfalls umständlich und eingeschränkt
- ORM bildet Domänenrepräsentation und Datenbankrepräsentation aufeinander ab, doch die Abstraktion kann undicht sein und Probleme verursachen
- Wenn Daten anders indiziert werden müssen als es der idealen Domänenrepräsentation entspricht, ist Adapter-Code nötig, und die effizient ausführbaren Abfragen können eingeschränkt sein
Komplexes Deployment und das à-la-carte-Modell
- Ein vollständiges Backend besteht nicht nur aus einer Datenbank, sondern benötigt viele Werkzeuge wie Datenbank, Verarbeitungssystem, Monitoring-Tools und Scheduler
- Ein großes Backend kann die Kombination von Dutzenden Werkzeugen erfordern, und Application-Updates wachsen zu einer Orchestrierung aus Migrationen, Code-Updates und Infrastrukturänderungen heran
- Für Produktionsreife ist ausreichende Telemetry nötig, doch weil jedes Tool anders sammelt, wird selbst das Zusammenführen in ein einziges Monitoring-Dashboard zu einer separaten Engineering-Aufgabe
- Das heute dominierende Entwicklungsmodell ähnelt einem à-la-carte-Modell, bei dem für jeden Architekturteil das jeweils beste Werkzeug ausgewählt und angefügt wird
- Schon die Arbeit, unabhängig entworfene Tools gemeinsam lauffähig zu machen, ist groß; durch feste Datenmodelle und eingeschränkte Schemata wird zudem eher die Anwendung an die Tools angepasst als umgekehrt
- Das à-la-carte-Modell hat sich etabliert, weil es kein kohärentes Modell für den Aufbau von Backends gab; in einem kohärenten Modell gibt es mehr Raum für Abstraktion, Automatisierung und Wiederverwendung
Ein einfaches Modell für Backends
- Die Hauptfunktionen eines Backends sind neue Daten anzunehmen und Fragen zu diesen Daten zu beantworten
- Die allgemeinste Form einer Abfrage lässt sich als Ausführung einer Funktion über alle vom Backend empfangenen Daten ausdrücken
query = function(all data)
- Praktisch kann ein Datensatz 10PB groß sein und eine Antwort in Millisekunden erfordern, daher braucht ein nutzbares System Indizes
- Mit hinzugefügten Indizes lässt sich das Modell so ausdrücken
indexes = function(data)query = function(indexes)
- Bestehende Backends setzen die Bestandteile dieses Modells durch mehrere eng spezialisierte Tools um
- Ein RDBMS-Backend nutzt das RDBMS für Daten und Indizes und kann für zusätzliche Indizierung eine separate Datenbank wie ElasticSearch einsetzen
- Berechnungen laufen oft in API-Server-Handlern oder in Background-Jobs auf Basis von Queues und Workern
- Große Backends können Tools wie Cassandra, MongoDB, Neo4j, Kafka, Hadoop, Storm und Kafka Streams kombinieren
- Daraus folgt die Schlussfolgerung, dass sich die zuvor beschriebene Komplexität vermeiden ließe, wenn es ein Tool gäbe, das alle Komponenten integriert und universell umsetzt
Aufbau von Rama und das Mastodon-Beispiel
- Rama ist eine auf diesen Prinzipien basierende Backend-Entwicklungsplattform
- Red Planet Labs stellte Rama am 15. August mit dem Tagline „the 100x development platform“ vor
- Als Beispiel für Kostensenkung wird eine Mastodon-Neuimplementierung im Twitter-Maßstab genannt
- 100M Bots posten 3.500-mal pro Sekunde
- Der durchschnittliche fanout liegt bei 403
- Zum Vergleich soll das entsprechende Twitter-Consumer-Produkt 1M Zeilen und rund 200 Personenjahre erfordert haben
- Die Rama-Implementierung benötigte 10k Zeilen und 9 Personenmonate
- Die Implementierung ist open-source und wird als complete, high-performance, production-ready beschrieben
- Zum Erreichen der nötigen Größenordnung habe Twitter spezialisierte Datenbanken wie eine social graph database und eine in-memory timeline database selbst gebaut und ein komplexes Deployment mit allein mehr als 1M Zeilen Puppet-Konfiguration betrieben
- Die auf Rama basierende Implementierung habe ähnliche Performance- und Skalierungsprobleme gelöst, indem sie die primitiven Bausteine von Rama kombinierte, statt für jedes Teilproblem spezialisierte Infrastruktur neu zu bauen
- Die performance numbers der Mastodon-Implementierung werden als gleich gut oder besser als die von Twitter dargestellt
Das Programmiermodell von Rama
- Die Konzepte von Rama entsprechen direkt dem zuvor beschriebenen Backend-Modell
- Depots: verteilte Logs für beliebige Daten, entsprechend
data - PStates: Kurzform für partitioned state, entsprechend den Indizes
- ETLs: entsprechend
function(data) - Queries: entsprechend
function(indexes)
- Depots: verteilte Logs für beliebige Daten, entsprechend
- PStates lassen sich in beliebiger Anzahl als beliebige Kombination langlebiger Datenstrukturen erzeugen
- ETL und query werden mit einer Turing-complete Dataflow-API beschrieben, und die Berechnungen können verteilt ausgeführt werden
- Rama stellt eine Java-API-Tutorial-Dokumentation bereit und bietet auch eine Clojure API
Wie Rama Datenbank-Komplexität reduziert
- Die PStates von Rama übernehmen eine ähnliche Rolle wie Datenbanken, können aber nur in der ETL topology beschrieben werden, die den jeweiligen PState besitzt
- Weil alle Schreibvorgänge im selben ETL-Code liegen, wird die Zustandslogik leichter nachvollziehbar
- PStates arbeiten als materialized views über einem Event-Sourcing-Log
- Da depot data die Source of Truth ist, können PStates neu berechnet werden
- Beschränkungen von Datenmodellen werden dadurch adressiert, dass PStates als Datenstrukturen definiert werden
- Die Mastodon-Implementierung nutzt allein für profiles, statuses und timelines 33 PStates
- Manche PStates decken 10 Use Cases ab, andere nur einen einzigen
- PStates besitzen die Eigenschaften durable, partitioned und incrementally replicated
- Incremental replication bedeutet, dass beim Ausfall einer Leader-Partition bereits eine andere Partition zur Übernahme bereitsteht
- Sichtbares auf dem aktuellen Leader bleibt auch auf einem späteren Leader sichtbar
- Das Problem von Normalisierung und Denormalisierung wird durch die explizite Trennung von depots und PStates behandelt
- Das Problem eingeschränkter Schemata wird dadurch gemildert, dass die Domänenrepräsentation direkt verwendet wird
- allgemeine Datenstrukturen wie hash map und list
- Protocol Buffers
- verschachtelte Objektdefinitionen
- Unbekannte Typen behandelt Rama durch die Registrierung eines custom serializer
Deployment, Integration, Monitoring
- Rama-Anwendungen heißen modules; ein module kann mehrere depots, ETLs, PStates und query topologies enthalten
- Rama bietet eingebaute Mechanismen für Deployment, Updates und Skalierung eines module, die jeweils per one-liner im Terminal ausgeführt werden sollen
- Rama ist kein „all or nothing“-Tool, sondern so entworfen, dass es sich leicht mit anderen Systemen integrieren lässt und schrittweise in bestehende Architekturen eingeführt werden kann
- Als integrierte Plattform übernimmt Rama auch eigenes Monitoring
- Sammeln von Monitoring-Daten
- Verarbeitung
- Indizierung
- Visualisierung
- Die cluster UI telemetry dient dazu, die Leistung eines module zu verstehen, Probleme zu erkennen und zu diagnostizieren sowie den richtigen Zeitpunkt zum Skalieren zu bestimmen
Lernen und Einführungsweg
- Zum weiteren Lernen über Rama werden folgende Ressourcen genannt
- Wer Rama in der Produktion für neue Funktionen, zur Erweiterung bestehender Systeme oder zur Vereinfachung der Infrastruktur nutzen möchte, kann sich für die private beta anmelden
- Nutzer der private beta sollen nicht nur beim Erlernen von Rama, sondern auch beim Schreiben von Code, bei Optimierung und beim Testen unterstützt werden
1 Kommentare
Hacker-News-Kommentare
„Wie ich später erklären werde, ist der bessere Ansatz Event Sourcing und materialisierte Views“ – heißt das am Ende, die Lösung ist mehr Komplexität? Natürlich ist sie das.
Unsere Mastodon-Implementierung im Twitter-Maßstab ist ein direktes Beispiel. Für dieselben Features in großem Maßstab braucht sie buchstäblich 100-mal weniger Code als Twitter hätte schreiben müssen, und auch über 40 % weniger Code als die offizielle Mastodon-Implementierung. Nicht weil wir es beim zweiten Mal mit denselben Tools besser designt hätten, sondern weil sie auf einer grundlegend besseren Abstraktion basiert.
Ab einer gewissen Größenordnung wird jedoch alles zu einem Data-Engineering-Problem, und im Kontext des Gesamtsystems kann dieser Ansatz zur relativ einfachen Lösung werden. Der Rat „Nimm einfach mySQL/SQLite/Postgres“ ist nur so lange hervorragend, bis er es plötzlich nicht mehr ist.
Ich glaube ernsthaft, dass es für alle besser gewesen wäre, wenn Martin Fowlers ursprünglicher Artikel zu Event Sourcing nie geschrieben worden wäre. In 99 % der Fälle halte ich es für eine schlechte Idee.
Vielleicht habe ich etwas übersehen, aber der Artikel scheint Konzepte wie Concurrency, Isolation und Constraints vollständig auszulassen. Und diese „Query-Topologie“ wirkt weder deklarativ noch so, als würde sie die Verantwortung für Query-Planung/-Optimierung dem Autor abnehmen – vielmehr scheint sie sie auf ihn abzuwälzen. Hält man das wirklich für eine bessere Developer Experience?
Und ja, Ramas Query-Ansatz ist ein deutlich überlegener Ansatz. Dass man einen komplexen Query Planner braucht, liegt meist an den Grenzen der Art, wie Daten indiziert werden, insbesondere an der Spannung zwischen Normalisierung und Denormalisierung. In Rama ist es einfach, mehrere Views robust zu materialisieren, die bereits in der für die jeweilige Query benötigten Form vorliegen.
Ein Tutorial, das die Konzepte von Rama behutsam einführt, gibt es hier: https://redplanetlabs.com/docs/~/tutorial1.html
Zu der Aussage „Kein einzelnes Datenmodell kann alle Anwendungsfälle unterstützen“: Theoretisch gibt es keine Domäne oder endliche Menge von Domänen, die sich nicht präzise als Tupel von Dingen und Beziehungen modellieren ließe.
In der Praxis ist der Umfang einer bestimmten Datenbank/eines bestimmten Schemas meist auf ein Unternehmen oder einen Problembereich beschränkt, aber solange sich die Typen nicht unpassend überschneiden, ist auch das kein großes Problem. Wenn man nur bei den Namen vorsichtig ist, kann man einen Webhändler und eine Versicherung problemlos in dasselbe Schema stecken, und es funktioniert ausreichend gut.
Alles exakt in eine einzige Datenbank zu packen, ist eine Superkraft. Der wichtigste Grund, warum ich das so entschieden vertrete, ist, verteilte Transaktionen über mehrere Datenspeicher hinweg zu vermeiden. Wenn das gesamte Business innerhalb eines einzigen Transaktionssystems abläuft, wird die Semantik dramatisch einfacher.
Sobald Leute tatsächlich anfangen, Daten zu nutzen, ist ein großer DB-Server für eine Million Dollar viel billiger als ein redundantes Array billiger Datenbanken. Alle sparen Zeit – Entwickler, Analysten und Management; vielleicht mit Ausnahme einiger DBAs.
Selbst wenn das theoretisch alles wäre, ist die Implementierung ein weiteres dauerhaftes Problem. Die meisten Entwickler verstehen heute nicht gut, wie Datenbanken funktionieren und wie man sie nutzen sollte, und verwenden sie deshalb miserabel. Also hat man neue Datenbanken wie NoSQL geschaffen, um dieser Tatsache auszuweichen, und wollte weniger nachdenken und nur mehr Glue Code schreiben. Auch das hat sich als furchtbares Ergebnis herausgestellt.
Bald wird der Trend wieder umschlagen, „einfach eine große Datenbank“ wird wieder aus der Mode kommen, und ein weiteres „Einfachheits“-Paradigma wird auftauchen. Wie bei Microservices könnte dann statt „eine große Datenbank“ „viele kleine Datenbanken“ als einfach gelten. Wer die Geschichte nicht versteht, ist dazu verdammt, sie zu wiederholen.
Das ist wie in der allgemeinen Programmierung: Eine einzige Datenstruktur oder Kombination von Datenstrukturen kann nicht alle Anwendungsfälle unterstützen. Manchmal braucht man eine Map, manchmal eine Liste, ein Set, Kombinationen davon oder etwas völlig anderes.
Natürlich sind Datenstrukturen vielfältig, Performance wird gebraucht, und das Ganze wird zu einem so wichtigen Engpass, dass normale Leute es nicht anfassen dürfen und jede Änderung extrem sicher sein muss. Sicherheit gibt es auch noch. Was, wenn jemand einen Weg findet, von der Sektion für Entwicklungs-Bugs in den HR- oder den nur für Führungskräfte bestimmten Finanzbereich zu gelangen? Wer schon einmal ein allgemeines ERM-System implementiert hat, weiß, wie schwierig und schmerzhaft integrierte Systeme sind.
Das ist allerdings ein Extremfall. Mich würde interessieren, wie weit Leute bei der Verfolgung dieses Ideals gekommen sind und wie sie es gemacht haben. Ich habe noch nie ein Unternehmen gesehen, das mit einem einzigen System betrieben wird. Wie sieht es mit persönlichen Wissensmanagement-Systemen aus? Passt dort alles hinein? Nutzt man für schnelle Arbeiten nicht trotzdem Tabellenkalkulationen und für freie Formen Textdateien?
Sieht aus wie eine Sammlung von Buzzwords. Ich habe jahrelang bei einem der größten Unternehmen der Welt mit Datenbanken gearbeitet, aber den Begriff Topologie habe ich noch nie gehört.
Selbst wenn man damit Zeit sparen könnte, würde sie dafür draufgehen, Java und dieses Framework zu lernen. An Datenbanken selbst ist nichts falsch.
Ich wollte hier eine Texttabelle erstellen, aber die Seitendarstellung ist völlig kaputtgegangen, deshalb poste ich es als Screenshot: https://imgur.com/a/XtwSkyx
Was ist Rama, wenn man es einem fünfjährigen Kind erklären müsste? Die Dokumentation hat mich auch verwirrt: https://redplanetlabs.com/docs/~/index.html
Bitte ohne Buzzwords wie „Paradigmenwechsel“ oder „Plattform“. Wenn ein Diagramm nötig ist, würde ich gern einen Artikel lesen, der es klarer erklärt.
Rama läuft als Cluster, und mehrere Anwendungen werden in Form von „Modulen“ auf diesem Cluster bereitgestellt. Tiefgehende, detaillierte Telemetrie ist ebenfalls integriert.
Das Programmiermodell von Rama besteht aus Event Sourcing und materialisierten Views. Beim Erstellen einer Rama-Anwendung materialisiert man so viele Indizes wie nötig, in der gewünschten Form, als Kombination mehrerer persistenter Datenstrukturen. Indizes werden über eine verteilte Dataflow-API materialisiert.
Rama unterscheidet sich so stark von allem Bisherigen, dass dies ungefähr die abstrakteste Erklärung ist, die ich geben kann. Die beste Ressource zum Lernen der Grundlagen ist rama-demo-gallery; sie enthält kurze, vollständig lauffähige und ausführlich kommentierte Beispiele, die Rama auf verschiedene Anwendungsfälle anwenden. Alle sind skalierbar und fehlertolerant: https://github.com/redplanetlabs/rama-demo-gallery
Es gibt ein append-only Event Log namens „Depot“, auf dem beliebige Views erstellt werden, die „P-States“ heißen. Die Rama-Software verspricht Updates dieser Views mit niedriger Latenz. Anwendungen, die darauf aufbauen, fragen die Views ab und senden neue Events/Commands an das Depot.
Ich habe ein einjähriges Projekt gemacht, in dem wir eine flexible Engine für materialisierte Views auf einem Live-Event-Datensatz im Bereich von 1–10 TB gebaut haben, und bevor ich zu einem anderen Projekt gewechselt bin, konvergierte unsere Architektur grob in Richtung der Idee, den Code dorthin zu schicken, wo der Index liegt.
Rama reizt mich ziemlich, aber aus einem völlig irrationalen Grund werde ich es wohl wegen der JVM nicht einführen. Ich mag Java/JVM einfach nicht. Ich würde mir wünschen, dass diese Architektur in andere Umgebungen portiert wird.
Auf der Arbeit trennen wir Lese- und Schreibmodell. Das Schreibmodell, also die Source of Truth, ist ein traditionelles relationales Domänenmodell samt Invarianten/Constraints, und ich denke, für die meisten Entwickler, die mit ORMs vertraut sind, ist es nicht schwer nachzuvollziehen.
Fast alle Commands erzeugen auch ein Event und veröffentlichen es in einer gemeinsamen Domain-Event-Queue. Die Lesemodelle werden von Workern aufgebaut, die Events konsumieren und ihre Views jeweils so erstellen, wie sie sie brauchen; sie können auch neu aufgebaut werden. Zum Beispiel ist ein User-Management-Service die Source of Truth, während andere Services als View-Services für komplexe UIs dienen und auf Basis von Events des User-Service und anderer Services eigene Lesemodelle/Indizes erstellen. Ohne das wären riesige Joins oder langsame serviceübergreifende API-Aufrufe nötig.
Technisch ist Event Replay möglich. Tatsächlich mussten wir wegen eines Bugs im Plattformcode einmal alle Events der letzten drei Jahre erneut abspielen. Aber wirklich gebraucht haben wir das meiner Meinung nach fast nie. Manchmal muss man wegen eines Bugs eine View neu erstellen, aber normalerweise erledigen wir das mit Ad-hoc-Programmen wie Spezialskripten oder SQL-Migrationen. Ich weiß nicht genau, wie man unsere Architektur nennen würde, und ich habe noch niemanden sie „Event Sourcing“ nennen hören.
Am Ende ist es altes MySQL + RabbitMQ und etwas Glue Code. Wenn man es richtig machen will, ist es aber wegen Transactional Outbox, mindestens-einmal-Zustellgarantie, eventual consistency, Beibehaltung der richtigen Event-Verarbeitungsreihenfolge, Batching von Event-Daten, DB-Management, Umgang mit abgestürzten Event-Handlern usw. nicht ganz trivial. Da wir bereits ein in der Praxis bewährtes, sprachunabhängiges Setup haben, mit Produzenten/Konsumenten in PHP und Go, frage ich mich, was uns ohne Rama fehlt und wie Rama die Probleme aus der obigen Liste löst. Rama scheint stärker auf die Java-Welt ausgerichtet zu sein.
Ramas Indizes sind deutlich flexibler. Wenn man zum Beispiel eine verschachtelte Menge mit 100 Millionen Elementen braucht, ist das trivial. Ein Social-Graph-Index wie User-ID → Menge von Follower-IDs ist ein typisches Beispiel. Ebenso einfach sind nach Granularität aufgeteilte Zeitreihenindizes, also Entität → Granularität → Zeit-Bucket → Statistik.
Bei den in Rama gespeicherten Datentypen gibt es keine Einschränkungen. Rama-Abfragen sind sehr leistungsfähig, und verteilte Echtzeit-Abfragen on demand über Teile oder die Gesamtheit eines Index sind einfach. Tiefgehende, detaillierte Telemetrie über die gesamte Anwendung hinweg ist ebenfalls integriert, sodass man sie nicht separat bauen oder verwalten muss.
Deployment ist ebenfalls integriert. Bei eurem aktuellen Ansatz können Anwendungsupdates mehrere Systeme betreffen, etwa Worker-Code und Schema-Migrationen, und besonders wenn man Zero Downtime möchte, wird das zu einer ziemlich schwierigen Engineering-Aufgabe. Rama integriert Berechnung und Speicherung durchgängig, sodass Release, Update und Skalierung einer Anwendung mit einer einzigen Terminal-Zeile möglich sind.
Rama ist deutlich besser skalierbar. Das ist Rama aus Funktionssicht; wie groß der Unterschied ist, wenn man beim Programmieren mit Rama keinen Impedance Mismatch hat, lässt sich schwer in Worte fassen – man muss es ausprobieren. Rama ist für die JVM gedacht, kann also mit jeder JVM-Sprache genutzt werden und bietet derzeit Java- und Clojure-APIs.
Wo und in welchem Format werden die Events gespeichert? Ich würde gern mehr Details hören.
Was derzeit fehlt, scheint ein schicker Name für das gesamte Ökosystem zu sein.
Wenn Daten zum Zeitpunkt der Änderung materialisiert werden, kann das von Vorteil sein, wenn ein Produkt eine Sache sehr schnell erledigen muss. Problematisch wird es aber, sobald komplexe Transaktionen entstehen, die gemeinsam über atomare Schreibvorgänge aktualisiert werden müssen, oder sobald man ein neues Feature hinzufügen möchte, das Daten auf andere Weise organisieren muss.
Auch dass im Abschnitt zum Aufbau von Anwendungen nach dem Motto „man hängt einfach einen Index dran“ darüber hinweggegangen wird, ist sehr unbefriedigend. Ein Index ist globaler Zustand, er wurde nur eine Ebene tiefer verschoben.
Auch nach dem Lesen dieses Dokuments ist nicht klar, wer die Zielgruppe ist und welches Problem gelöst werden soll: https://redplanetlabs.com/docs/~/why-use-rama.html#gsc.tab=0
Es wäre hilfreich, einen echten Anwendungsfall zu nehmen und zu zeigen, wie einfach und effizient die Umsetzung mit RAMA wäre.
Das erste ist eine Mastodon-Implementierung in Twitter-Größenordnung; sie benötigt 100-mal weniger Code als der Code, den Twitter geschrieben hat, um dasselbe in großem Maßstab zu bauen. Dabei geht es nur um das Consumer-Produkt. Sie hat sogar über 40 % weniger Code als die offizielle Mastodon-Implementierung, die nicht skalierbar ist: https://github.com/redplanetlabs/twitter-scale-mastodon
Im Repository rama-demo-gallery gibt es außerdem viele kurze, eigenständige und ausführlich kommentierte Beispiele, die Rama auf sehr unterschiedliche Anwendungsfälle anwenden. Dazu gehören die Verwaltung von Nutzerprofilen, Zeitreihenanalyse sowie atomare und fehlertolerante Banküberweisungen: https://github.com/redplanetlabs/rama-demo-gallery
Wenn man nicht tatsächlich eine Website mit 40 Millionen täglichen Nutzern betreibt, scheint man nicht behaupten zu können, dass ein „Mastodon-Client in Twitter-Größenordnung“ das beweist. Eine reale Umgebung, die daraus folgenden Änderungen an Code und Infrastruktur, echte Nutzer, Netzwerkauslastung usw. lassen sich nicht simulieren.