Morphium in der Version 5

Info

Datum: 15. 11. 2022 um 23:05:42

Schlagworte: Java MongoDB Morphium

Kategorie: morphium

Ursprünglich veröffentlicht auf: caluga.de

erstellt von Stephan Bösebeck

logged in

ADMIN


Morphium in der Version 5

Morphium V5

Morphium entstand im Jahr 2012 und hat seit dem 4 größere Releases bekommen. Jetzt ist es an der Zeit, etwas mehr zu aktualisieren und einige Interna anzupassen.

Ziele des Rewrites

Ziel ist es, alte "Zöpfe" abzuschneiden und den Code zu aktualisieren. Es soll dabei möglichst kompatibel bleiben, dass eine Migration leicht möglich ist.

Des weiteren sollte die Komplexität reduziert werden, wir haben einige Features in Morphium die sicherlich kaum bis gar nicht genutzt werden, wie z.B. "optimisic locking" mit Hilfe von automatischer Versionierung. Diese "Features" werden entfernt und damit wird der Code entschlackt.

Des Weiteren soll Morphium weiterhin kompatibel mit den älteren Versionen bleiben. D.h. die Änderungen an Morphium selbst werden sich in Grenzen halten. Auch die Konzepte werden sich nicht ändern, allerhöchstens etwas verschärft werden. So ist Morphium weiterhin der Dreh- und Angelpunkt der API und es wird weiterhin jeder Schreibzugriff über Morphium und jeder lesezugriff über Query laufen (Ausnahme: Aggregation mit Hilfe des Aggregators). Kurzum: die Nutzung von Morphium ändert sich im wesentlichen nicht.

JDK 11

Beim Refresh sollte auch das verwendete JDK aktualisiert werden. Morphium V4 bleibt auf JDK1.8, ab V5 werden wir JDK11 und folgende unterstützen. Dabei soll natürlich auch der Code die neuen Features von JDK11 nutzen.

Morphium Object Mapping

Der Morphium Object Mapper ist in aktuellen Tests immer noch einer der schnellsten und feature reichsten Object-Mapper, den wir so gefunden haben. Im Vergleich mit Jackson muss man insbesondere die höhere Performance und auch die Features beim Handling von Listen und Maps (Handling von Generics) erwähnen - das macht den MorphiumObjectMapper wirklich unverzichtbar.

Beim Rewrite wurden aber einige Features, die sich auch im ObjectMapping wiederspiegeln, entfernt, wodurch der Code vereinfacht und wartbarer wird.

Morphium Cache und WriteBuffer

Morphium hatte von Anfang an eine deklaratives Caching als Teil des Systems. Dieses ist auch weiterhin ein zentraler Berstandteil. Der Cache implementiert die JCache - API und könnte somit auch für andere Zwecke genutzt werden. Andersrum kann man auch einen JCache in Morphium für das Caching nutzen.

Beim Rewrite werden wir den Code auf JDK11 anpassen und die Struktur des Codes verbessern.

Morphium Messaging

Ein weiterer zentraler Bestandteil ist das Messaging. Besonderes Augenmerk beim Messaging wird sein, die Stabilität zu verbessern und die Last zu verringern. Insbesondere durch effizientes Verwenden der Driver-API und des WireProtocol. Eine weitere Änderung wird das Connection Handling in Messaging sein: aktuell nutzt das Messaging Morphium selbst als Connector zur Mongo. Da beim Messaging keine der Features von Morphium nötig sind bzw. teilweise sogar eher hinderlich sind, wird in der V5 das Messaging direkt mit der MongoDB kommunizieren. In der Aktuellen V5-Implementierung nutzt das Messaging eine dedizierte Verbindung zur MongoDB für die Push-Notifications (Watch) und einen dedizierten Connection Pool für die Verbindung zur Mongo. Dadurch ist das Messaging etwas lostgelöster von Morphium, erzeugt weniger Last und kann gesondert konfiguriert werden. Das ist mittlerweile implementiert, die Tests zeigen, dass dadurch die Last auf Mongo verringert, die Antwortzeit reduziert wird.

MorphiumConfig

Dieses "Ding" ist über die Jahre auch ein wenig gewachsen und ist momentan mit den 100en gettern und settern kaum noch sinnvoll zu benutzen. Die Settings müssen ein wenig aufgespalten werden und in verschiedenen Kategorien eingesetzt. Insbesondere, weil der Morphium-eigene Wire-Protokol-Treiber andere Settings benötigt, als z.B. der InMemDriver.

Konzentration auf die Community Edition

Wir implementieren das allerdings nur für die Community Edition. D.h. die Enterprise-Features finden in dem Rewrite keine Beachtung. Es kann auch dazu führen, dass die Treiber mit der Enterprise MongoDB-Version nicht sauber funktionieren. Gleiches gilt aktuell auch für die Atlas-MongoDB-Implementierung, welche sicher als erstes nachgereicht wird. Support der Enterprise-Edition Features wird evtl. bei Bedarf auch in einer der folgenden Versionen implementiert werden.

Rewrite Bottom up

Der Rewrite erfolgt von "unten", d.h. zuerst wurde der Mongo-Treiber (s.u.) implementiert, der das Wire-Protokoll realisiert (Aktuell nur für MongoDB ab V5 verwendbar! für ältere MongoDB-Versionen bitte Morphium V4.x verwenden!).

Die Notwendigkeiten und die Struktur dieses Treibers wird hauptsächlich von der MongoDB bestimmt und propagiert die Architektur nach "oben". Auf dem Weg dahin, werden ungenutze Features entfernt (wie z.B. Auto-Versioning), andere allein durch die Anpassung an die neuen Treiber verbessert.

Am Ende sollte ein Morphium raus kommen, welches nahezu 100% source kompatibel zur alten Version ist, aber viel moderner, schlanker, schöner!

Morphium Treiber

Morphium ist mehr oder minder ein Ersatz für den bestehenden MongoDB-Treiber mit einer Menge mehr Features und an einigen Stellen deutlich mehr Sicherheit und / oder Performance.

Aktuell (also in Morphium V4.x) gibt es 2 Treiber: MongoDriver und InMemDriver. Insbesondere der MongoDriver erzeugt ein wenig Overhead, weil er auf dem offiziellen MongoDB-Treiber aufsetzt, welcher dummerweise mittlerweile nicht nur ein Treiber, sondern eben auch ein Object-Mapper ist. Viele Funktionen des Treibers werden gar nicht benötigt, dafür fehlen einige andere. Ziel ist es also, einen eigenen WireProtocol[^1:WireProtokoll ist das Protokoll welches MongoDB zur Kommunikation nutzt]-Treiber einzuführen, der auf die Bedürfnisse von morphium hin optimiert ist. Dadurch kann ein signifikanter Performance-Vorteil erlangt werden (aktuell zw. 10% und 20%).

Es werden 2 Treiber implementiert:

  • SingleConnectDriver- ein Treiber, der nur eine einzige Verbindung zur MongoDb hält, diese aber überwacht und bei Bedarf auch einen Failover realisiert. Dieser wird z.B. in dem neuen Messaging-Unterbau verwendet (s.u.)
  • PooledDriver - ein full featured cluster connector mit Connection Pooling und automatischem Failover.

InMemory Driver

Streng genommen gibt es noch einen dritten Treiber, den InMemoryDriver, welcher es möglich macht, Morphium mit einer "in Memory"-Mongo zu betreiben. Dies ist insbesondere für Tests sinnvoll. Das nutzen wir in einigen Projekten als TestDB und ist auch vergleichbar mit anderen für Testzwecke implementierten Datenbanken. Die InMemory Datenbank sollte (Nahezu) feature kompatibel zu einer echten MongoDB Installation sein. Wir sind noch nicht 100% so weit, aber bei gut 90% angekommen. Die meisten Features funtkionieren aber schon, einige Dinge benötigen allerdings noch etwas länger und könnten evtl. erst später kommen (wie z.B. "echte" Text indexe).

Warum nicht der MongoDB Treiber

Diese Frage wird häufiger gestellt und ich möchte ein paar Worte dazu verlieren:

Features des Treibers

Der offizielle MongoDB-Java-Treiber ist nicht nur ein Treiber, sondern in den Treiber "eingebettet" ist auch ein Object-Mapper. Das ist für viele Anwendungen vermutlich super sinnvoll und völlig ausreichend.

Für uns jedoch leider nicht, da wir einige Dinge eher konfigurieren, denn programmieren wollen (Deklarative Indices etc.).

Da krachen zwei verschiedene Denkweisen aufeinander. Was im Beispiel des MongoDB-Treibers und Morphium immer mal wieder zu... Unstimmigkeiten geführt hat. Einige Änderungen an der Treiber API haben in Morphium echt ne Menge Arbeit bedeutet.

Es gab schon seit ein paar Jahren das Projekt MorphiumDriver. Es wurde ins Leben gerufen, weil wir mit dem offiziellen MongoDB-Treiber leider immer wieder Probleme gerade im Bereich des Failover hatten. Außerdem sind einige Features des Treibers meiner Meinung nach zumindest ein wenig fragwürdig.

Diese Features, insbesondere das ObjectMapping, machen den Zugriff via Morphium ein wenig unhandlich. Und einige Dinge passieren unnötigerweise doppelt. Und genau deswegen wollen wir versuchen einen eigenen Treiber zu entwickeln, der genau das macht, was wir benötigen - und nicht mehr.

Aktuell gibt es beim Zugriff auf die Mongo im Stacktrace gut und gerne mal 20Calls innerhalb des MongoDB-Treibers. Mit dem neuen Treiber sind das maximal 5!

neues Feature: InMemoryServer

Morphium in der Version 5 hat einen eigenen Server spendiert bekommen, welcher auch auf die InMemory Datenbank aufsetzt. Dieser ist naturgemäß ausschließlich für Testzwecke gedacht und bietet keinerlei sicherheit oder ähnliches. Für die Tests von einer (simplen) in Memory Mongodb ist es aber allemal hilfreich (mit den Einschränkungen des InMemoryDrivers). Wer das jetzt schon testen möchte:

java -cp morphium-5.0.0-SNAPSHOT.jar de.caluga.morphium.server.MorphiumServer

Der MorphiumServer versteht folkende Kommandozeilenoptionen:

  • -mt oder --maxThreads: maximale Anzahl von Threads im Server (= maximale anzahl von Verbindungen)
  • -mint oder --minThreads: ninimale Anzahl von Threads (werden bereit gehalten)
  • -h oder --host: als welcher host meldet sich dieser Server zurück (in der Antwort zum hello oder isMaster Kommando)
  • -p oder --port: welcher Port soll geöffnet werden (alle Netzwerk-IPs)

Ich möchte noch mal betonen, dass dieser Server rein für Testszwecke gedacht ist und sicherlich kein Ersatz für irgendwelche MongoDB-Installationen sein soll.

Migration

Die Migration sollte relativ einfach von Statten gehen, da die API von Morphium selbst sich nicht geändert hat. Jedoch hat sich die Konfiguration angepasst:

  • es wurden die KlassenNamen entfernt. Es macht keinen Sinn, eine eigene Query-Implementierung einzubinden. Zumindest war uns nicht bekannt, dass das irgendwer getan hätte. Gleiches gilt für die definierten Factories etc.
  • Die Treiber werden nicht mehr über den ClassName referenziert, jetzt gibt man den DriverName an. Gültige Treiber aktuell sind: InMemoryDriver, SingleConnectionDriver, PooledDriver, MongoDriver. Der MongoDriver funktioniert aktuell leider nicht und es ist nicht 100% sicher, dass er Teil von Morphium bleibt
  • der Zugriff auf den Treiber direkt - falls das jemand gemacht haben sollte - ist zwar immer noch möglich, aber die Treiber-API hat sich gravierend geändert. Deswegen muss man hier mit größeren Umbauarbeiten rechnen.
  • das optimistic locking -Feature wurde entfernt. Alle, die dieses Feature genutzt haben, müssen aktuell leider eine eigene Implementierung suchen

Aktueller Stand

Aktuell, Ende August 2022, ist Morphium V5 als ALPHA-Version in Maven-Central verfügbar und kann für eigene Tests genutzt werden. Jedoch sind einige Features noch nicht 100% implementiert. So funktioniert Morphium nur mit MongoDB-VErsionen ab 5.0. Außerdem funktioniert momentan das Transaction-Feature nicht. Der noch aktuellere Stand, November 2022, ist: Morphium V5 wird in die BETA-Phase übergehen. Aktuell laufen alle tests durch (mehr als 800 Testcases werden abgedeckt!)

Testen

Die Tests waren immer in wichtiger Bestandteil der Entwicklung. Wir haben aktuell ca. 900 Testcases, von denen einige mit 3 verschiedenen Implementierungen laufen (Parameterized Tests). Wir haben viel Zeit investtiert, die Tests seiteneffektfrei zu gestalten. So wird jedem Testrun eine eigene Datenbank zugewiesen, alle anderen Datenbanken werden gelöscht.

Um die tests effizienter und einfacher "nebenbei" laufen zu lassen, haben wir ein Script gebaut, welches alle Tests (bzw. bei Bedarf einzelne) laufen lässt. So ein Run dauert gut und gerne mal 2h.

Plan

in den nächsten Wochen werden diese Dinge in dieser Priorität angegangen:

  1. Stabilität / Failover etc testen und evtl. anpassen: die Tests sind natürlich nur bedingt fähig, echte Fail-Szenarien zu testen. Das müssen wir noch testen.
  2. Auto Retry read/write überall implementieren: für jeden DB-Zugriff soll gemäß den Vorgaben von MongoDB ein Retry geschehen (im Offiziellen Treiber kann man das aber abschalten). Es muss sicher gestellt werden, dass das bei allen implementiert wurde.
  3. InMemoryDriver fertigstellen und fehlende Features implementieren: der InMemoryDriver ist schon deutlich fähiger geworden, als noch zu V4 Zeiten. Allerdings fehlen einige Features noch, damit er wirklich zum Testen von allem genutzt werden kann. So fehlen die GeoSphere-Funktionalitäten, einige Javascript Funktionen, und ein paar besondere Befehle noch.
  4. MorphiumConfig umschreiben und alte Settings entfernen, neue anpassen, evtl. modularer gestalten: ein größeres TODO, aktuell ist die MorphiumConfig noch vergleichbar mit der "Alten" Version, evtl. wird sich das aber in der nächsten Zeit noch ändern
  5. Transaction handling implementieren (auf Treiber-Ebene, morphium unterstützt das längst): Das ist ncoch ein kleineres Problem: ich habe bisher nicht rausgefunden, wie der Treiber eine Transaktion startet.
  6. MongoDriver fertig implementieren oder entfernen: Aktuell gehen wir davon aus, den MongoDb-Treiber zu entfernen, weil er immer wieder Probleme bereitet im Zusammenspiel mit Morphium.