Es gibt nur sehr wenige Szenarien, in denen eine datenbank mit eventueller Konsistenz einer datenbank mit starker Konsistenz vorzuziehen ist. Darüber hinaus ist in einem Multi-Region-Anwendungsszenario, in dem Skalierung erforderlich ist, die Wahl einer nicht verteilten datenbank oder einer datenbank mit eventueller Konsistenz noch fragwürdiger. Was also motiviert Ingenieure, stark konsistente verteilte datenbanken zu ignorieren? Wir haben viele Gründe gesehen, aber falsche Annahmen treiben die meisten von ihnen an.
„Das CAP-Theorem besagt, dass es unmöglich ist“
Wie wir in Teil 1 dieser Serie erklärt haben, wird das CAP-Theorem weithin akzeptiert, aber oft missverstanden. Wenn viele Menschen einen bekannten Satz missverstehen, hinterlässt das Spuren. In diesem Fall glauben viele Ingenieure immer noch, dass eventual consistency ein notwendiges Übel ist.
„Der Bau einer stark konsistenten verteilten Datenbank ist zu schwierig/unmöglich“
Es sickert langsam durch, dass Konsistenz nicht geopfert werden sollte, aber viele Datenbanken stellen die Konsistenz immer noch an zweite Stelle. Warum ist das so? Einige beliebte Datenbanken bieten Optionen, die eine höhere Konsistenz liefern, aber nur auf Kosten potenziell sehr hoher Latenzen. Ihre Verkaufsbotschaften behaupten vielleicht sogar, dass die Bereitstellung von Konsistenz bei geringen Latenzen in einer Multi-Region-verteilten Datenbank unglaublich schwierig oder sogar unmöglich ist, und das Entwicklerpublikum hat lebhafte Erinnerungen an sehr schlechte Latenzen bei Datenbanken, die nicht auf Konsistenz ausgelegt waren. Zusammen befestigen sie gemeinsam die Fehlannahme, dass starke Konsistenz in einer verteilten Datenbank mit relativ geringen Latenzen unmöglich ist.
„Voreilige Optimierung ist die Wurzel allen Übels“
Viele Ingenieure bauen nach dem Prinzip „Voreilige Optimierung ist die Wurzel allen Übels“ (Donald Knuth), aber diese Aussage soll sich nur auf kleine Ineffizienzen beziehen. Den Aufbau Ihres Startups auf einer stark konsistenten, verteilten und skalierbaren Datenbank mag wie eine voreilige Optimierung erscheinen, da Ihre Anwendung anfangs keine Skalierung benötigt und möglicherweise keine Verteilung erfordert. Hier sprechen wir jedoch nicht von kleinen Ineffizienzen. Die Notwendigkeit zu skalieren oder zu verteilen kann über Nacht entstehen, wenn Ihre Anwendung beliebt wird. Zu diesem Zeitpunkt haben Ihre Benutzer eine schreckliche Erfahrung, und Sie stehen vor einer erheblichen Herausforderung, Ihre Infrastruktur und Ihren Code zu ändern.
„Es ist schwierig, gegen eine verteilte Datenbank zu programmieren“
Das hatte früher eine gewisse Wahrheit, da verteilte Datenbanken neu waren und viele schwere Einschränkungen hatten. Sie erlaubten keine Joins, erlaubten nur Schlüssel-Wert-Speicher oder verlangten, dass Sie Ihre Daten anhand vordefinierter Sharding-Schlüssel abfragen, die Sie nicht mehr ändern konnten. Heute gibt es verteilte Datenbanken mit flexiblen Modellen, die Ihnen die Flexibilität bieten, die Sie von traditionellen Datenbanken gewohnt sind. Dieser Punkt ist eng mit dem vorherigen Punkt verbunden, der ignoriert, dass das Programmieren gegen eine stark konsistente verteilte Datenbank heutzutage genauso einfach und wahrscheinlich auf lange Sicht einfacher ist als gegen eine traditionelle Datenbank. Wenn es genauso einfach ist, warum dann nicht von Anfang an optimieren?
Mit einer eventually consistent Datenbank zu arbeiten ist wie…
Verteilte Datenbanken werden oft von Leuten entwickelt, die Probleme mit eventual consistency hatten. FaunaDB zum Beispiel wurde von ehemaligen Twitter-Ingenieuren entwickelt, nachdem sie erlebt hatten, wie schwierig es ist, ein skalierbares System auf den damals populären, eventually consistent Datenbanken wie Cassandra aufzubauen. Diese Probleme treten typischerweise auf, wenn ein neues Unternehmen zu skalieren beginnt, daher haben viele jüngere Ingenieure sie nie aus erster Hand erlebt.
Manchmal können schmerzhafte Dinge uns Lektionen lehren, von denen wir nicht dachten, dass wir sie wissen müssten.
— Amy Poehler
Die Diskussion über die Gefahren von eventual consistency führt typischerweise zum Argument „es funktioniert für mich“ von Ingenieuren, die einfach noch keine Probleme hatten. Da das oft Monate (oder Jahre, wenn man Glück hat) dauert, betrachten wir eine Analogie.
…mit einem Fahrrad mit lockeren Rädern zu fahren.
Vor einiger Zeit musste mein bester Freund zu einem Termin und ich lieh ihm mein Fahrrad. Ich war glücklich, dass ich geholfen hatte, er war glücklich und alles lief gut. Dieses Glück verwandelte sich schnell in Schmerz, als er versuchte, mit dem Fahrrad auf einen Bürgersteig zu springen. Sehen Sie ... ich hatte am Tag zuvor mit dem Fahrrad gebastelt und vergessen, das Vorderrad festzuziehen. Er kam mit einem riesigen lila Bluterguss zurück.

Das Fahrradbeispiel ist dem Arbeiten mit einer Datenbank, die nicht stark konsistent ist, sehr ähnlich. Alles wird gut gehen, bis Sie versuchen, das Rad des Fahrrads anzuheben (oder anders ausgedrückt, bis Ihr Unternehmen abhebt und mit dem Skalieren beginnt).
Wenn Ihre Anwendung hochskaliert werden muss, tun Sie dies in der Regel durch Replikation von Diensten. Sobald die Datenbank zum Flaschenhals wird, replizieren Sie Ihre traditionelle Datenbank oder wechseln zu einer verteilten Datenbank. Leider können zu diesem Zeitpunkt Features in Ihrer Anwendung fehlschlagen, wenn Sie beginnen, Ihre Datenbank zu replizieren. Bis jetzt hatten Sie diese Probleme nicht bemerkt, da die Datenbank auf einem einzigen Knoten lief. Zu diesem Zeitpunkt können zwei Dinge passieren:
- Situation 1, darum herum bauen/reparieren: die Entwickler erkennen bald, dass die Datenbank, auf der sie „reiten“, für die Features, die sie entwickelt haben oder entwickeln wollen, unzuverlässig ist. Ihre Optionen sind, die Features zu stornieren, die Features zu vereinfachen oder die Datenbank zu wechseln.
- Situation 2, spektakulär scheitern: die Entwickler wurden vom Anbieter (ich war ein schlechter Fahrradverkäufer für meinen Freund) nicht über die Risiken informiert und ihnen fehlen nun die Informationen, um die sehr subtilen Auswirkungen dessen, was geschieht, zu verstehen. Dies ist nicht unbedingt auf mangelnde Fähigkeiten des Ingenieurs zurückzuführen. Schlecht definierte Standards und optimistische Vermarktung tun viel dafür, die Konsistenzgarantien verschiedener Datenbanken zu verschleiern.
Die Entwickler, die in die erste Situation geraten, sind oft bereits erfahren im Umgang mit eventually consistent Systemen. Sie werden nun entweder akzeptieren, dass sie einige Features nicht liefern können, oder eine komplexe und schwer zu wartende Schicht über der Datenbank aufbauen, um das zu bekommen, was sie brauchen. Im Wesentlichen versuchen sie, eine stark konsistente Datenbank auf einer eventually consistent Datenbank zu entwickeln. Das ist schade, da andere Leute verteilte Datenbanken von Grund auf neu entworfen haben, die nicht nur effizienter sind, sondern keine Wartung durch Ihr Entwicklungsteam erfordern!
…mit einem unsichtbaren Fahrrad mit lockeren Rädern zu fahren.
Die Entwickler, die in die zweite Situation geraten, fahren ein teilweise unsichtbares Fahrrad. Sie erkennen nicht, dass das Rad lose ist, sehen nicht, wie das Rad abfällt, und wenn sie nach dem Sturz aufblicken, sehen sie immer noch ein vollkommen intaktes Fahrrad.

Wenn die Dinge schiefgehen, ist die Komplexität der Fehlerbehebung aus mehreren Gründen hoch:
- Feststellen, ob es sich um einen Bug bei eventual consistency handelt. Das Problem könnte entweder ein Anwendungsfehler sein oder ein Fehler, der durch Missverständnisse der Garantien der zugrundeliegenden Datenbank verursacht wurde. Um sicher zu sein, müssen wir die Anwendungslogik untersuchen, und falls die Anwendungslogik in einer nicht-verteilten Umgebung einwandfrei ist, muss der Ingenieur den Instinkt haben, zu beurteilen, ob diese Situation aufgrund von eventual consistency entstehen könnte.
- Die Ursache ist verschwunden. Zweitens, da die Datenbank schließlich konsistent wird, ist die Ursache des Problems wahrscheinlich verschwunden (das Rad ist auf magische Weise wieder am Fahrrad befestigt, und alles, was Sie sehen, ist ein tadelloses Fahrrad).
- Beheben Sie es! Sobald das Problem festgestellt ist, können Sie entweder einen Weg darum herum finden, versuchen, eine Schicht über der Datenbank aufzubauen (hallo Latenz und andere potenzielle Fehler), Features entfernen oder die Datenbank wechseln. Letztere Option wird manchmal als einfach angesehen. Selbst die subtilsten Unterschiede zwischen Datenbanken machen dies jedoch zu einem sehr anspruchsvollen Unterfangen. Wenn Ihre Anwendung gerade abhebt, haben Sie bereits alle Hände voll zu tun. Dies ist nicht der Zeitpunkt, an dem Sie Datenbanken austauschen wollen!
…mit einem unsichtbaren Fahrrad mit lockeren Rädern und einer Gruppe von Leuten, die auf Ihren Schultern stehen, zu fahren.
Das unsichtbare Fahrradbeispiel ist immer noch zu nachsichtig. In Wirklichkeit hängen wahrscheinlich andere von Ihrer Anwendung ab. Sie fahren also im Grunde auf einem unsichtbaren Fahrrad, während andere (Ihre Kunden) auf Ihren Schultern stehen.

Nicht nur Sie werden stürzen, sondern sie werden mit Ihnen stürzen und auf Ihnen landen – schwer und schmerzhaft. Sie werden den Sturz zu diesem Zeitpunkt vielleicht nicht einmal überleben; mit anderen Worten, Ihr Unternehmen wird den Sturm negativer Rückmeldungen von Ihren Kunden möglicherweise nicht überstehen.
Die Moral von der Geschichte? Wenn Sie sich von Anfang an für eine stark (im Gegensatz zu eventually) konsistente Datenbank entschieden hätten, müssten Sie nicht in Betracht ziehen, ein komplexes und ressourcenintensives Projekt wie die Migration Ihrer Datenbank zu durchlaufen, zu einer Zeit, in der Ihre Kunden bereits frustriert sind.
Fazit
Die Wahl einer eventually consistent Datenbank für die Skalierung war vor einigen Jahren gerechtfertigt, als es einfach keine andere Wahl gab. Inzwischen haben wir moderne Datenbanken, die effizient skalieren können, ohne Datenkonsistenz oder Leistung zu opfern. . Darüber hinaus beinhalten diese modernen Datenbanken auch mehrere andere fantastische Funktionen, die über die Konsistenz hinausgehen, wie z. B. Benutzerfreundlichkeit, Serverless-Preismodelle, integrierte Authentifizierung, Temporalität, native GraphQL und mehr. Mit einer modernen Datenbank können Sie skalieren, ohne die Büchse der Pandora zu öffnen!
Und wenn Sie sich nach dem Lesen dieser Artikelserie immer noch dafür entscheiden, keine stark konsistente verteilte Datenbank zu verwenden, stellen Sie bitte zumindest sicher, dass Sie Ihre Räder festziehen (mit anderen Worten, lesen und verstehen Sie die Konsistenzgarantien verschiedener Datenbanken).