(Micro-)Services und das Composite DB Pattern

Kaum ein Softwareblog kommt heute noch am Thema Microservices vorbei, oder? Puristische Implementierungen sind mir von jeher fremd, jedoch nutze ich heutzutage verstärkt kleinteiligere Services und Microservice-Ansätze. Dabei ist ein Pattern entstanden, welches ich Microservices+Composite DB nenne.

Puristische Microservice-Ansätze propagieren lokale DataStores. Ich schätze dagegen die Vorteile einer monolithischen zentralen Datenbank (trotz natürlich vorhandener Nachteile) als sehr hoch ein. Dennoch habe ich immer nach Möglichkeiten gesucht, die Komplexität der zentralen Datenbank zu senken. Vor einiger Zeit habe ich eine Blog-Reihe über Entity Modellierung 2.0 geschrieben. Eine Idee war die echte Modularisierung in der Datenbank.

Aus diesen Grundideen sind gewissermaßen die Packages in SQL Link entstanden, auch wenn außerhalb von Modellierungssphären. SQL-Datenbanken können dabei aus modularen Paketen zusammengesetzt werden. Für den Admin sieht dies dabei wie ein Deployment-Monolith aus, die Programmierer pflegen jedoch kleinteiligere Schemas. Die Pakete stellen gerichtete Abhängigkeiten dar, das Ganze ist also keine Zauberei, sondern nur ein kleiner Aufsatz auf das relationale System. Eine so strukturierte Datenbank nenne ich auch Composite DB.

Auf Datenbank-Ebene werden alle Vorteile der starken Integrität z.B. in Form von Fremdschlüsseln genutzt. Auf Anwendungsebene (z.B. durch Zugriff via O/R Mapper) wird jedoch nur der Ausschnitt der Datenbank isoliert gelesen und bearbeitet.

Interessant wird es nun, wenn auf die feineren Modelle nicht von einer monolitschen GUI zugegriffen wird, sondern kleinere Services im Spiel sind.

Beispiel BlueScreen Licensing

Kürzlich habe ich ein Lizenzierungssystem selbst bauen müssen. Kurz danach ist mir aufgefallen, dass ich es vor 5 Jahren anders, monolithischer, konstruiert hätte. Das System ist recht klein, daher sind es nur Nuancen, aber letzlich sind es diese kleinen Abweichungen, welche die Vorteile von pragmatischen Microservices hervorragend demonstrieren.

Die Architektur:

licenseservices

Das System besteht aus zwei Teilen.

Zum Einen existiert die eigentliche Lizenzdatenbank mit einem öffentlichen ActivationService für Clients zur Validierung der Lizenzen und einem geschützten ManagementService zum Bearbeiten der Lizenzen. Das Datenmodell für die Lizenzdatenbank ist ein Paket in der Composite DB.

Hinzu kommt eine Integration für ein Reseller-System, bei dem z.B. aus Bestellungen automatisch Lizenzen generiert werden. Auch dieser Teil benötigt einige Tabellen und verwendet ein Paket in der Composite DB.

In diesem Beispiel ist ein Reseller angebunden, aber natürlich kann man sich leicht 5 oder 6 denken, was den Nutzen der Architektur weiter erhöht.

Physisch werden alle Services in dem selben WebHost (einer IIS-Anwendung) gehostet und können gemeinsam mit einem Klick bereitgestellt werden. Die Systeme könnten aber genausogut separat bereitgestellt werden, sofern die Datenbank kompatibel bleibt. Ein großer Vorteil von Microservices – das unabhängige Deployment – wird hier also genutzt.

Das Reseller-System ist übrigens in einer komplett anderen Technologie implementiert als das Kernlizenzsystem. Das Kernlizenzsystem nutzt WCF, die Reseller-Integration ASHX Web Handler. Das ist schon die erste feine Nuance. In einem monolitscheren System wäre mir das eher als negativer Aspekt aufgefallen. Das externe System schränkt aber auf rohe HTTP-Ebene ein. Die Auswahl stand zwischen WebAPI und ASHX. Normalerweise verabscheue ich diese verstaubte Low-Level-Technik von ASHX-Handlern und ziehe eine MVC/WebAPI immer vor. Aber für diese Art der Aufgabe ist es geeignet, hat keinerlei Abhängigkeiten und benötigt keine Romane in der Web.config.

Microservices können mit technologischer Vielfalt viel eher umgehen als reine Monolithen. Das Beispiel zeigt, dass es nicht immer um extreme Plattformvariabilität gehen muss. Viel wahrscheinlicher ist es, dass ein Systemteil in .NET 4.x und ein anderer in .NET  Core implementiert ist. .NET Core ist ein hervorragendes aktuelles Beispiel, aber auch die Umstellung anno dazumal von ASP.NET MVC 2 auf 3 hatte einige Inkompatibilitäten mit sich gebracht. Eine schrittweise Portierung von Microservice zu Microservice erlaubt eine kontinuierlichere Erneuerung und somit können Microservices plötzlich auf Geschäftsebene wichtige Vorteile bringen. Wir alle kennen ja die Geschichte von Netscape, die lieber ihre technische Basis komplett überholen wollten, anstatt Features rauszubringen und leider bis zum nächsten Public Release in der Bedeutungslosigkeit verschwunden sind.

Aber nochmal zurück zu den technischen Nuancen. In meinem Beispiel greifen die ResellerWebHooks nicht direkt auf die Lizenzdatenbank zu (physischer Zugriff wäre rein theoretisch vorhanden), sondern via ManagementService. Das hätte ich früher tatsächlich nicht über Services abgewickelt, sondern ggf. über gekapselte Domain Models, welche die vorhandene physische Datenbankverbindung genutzt hätten. Aber erst die Nutzung von Services entkoppelt soweit, dass die gemeinsame Datenbank zwar möglich, aber nicht zwingend erforderlich ist.

Fazit

Man muss nicht zwingend eine puristische Microservice-Architektur verwenden, um in den Genuss vieler Microservice-Vorteile zu kommen. Höchstwahrscheinlich haben geschickte Architekten schon vor Jahrzehnten solche Systeme entworfen und sich später an Flexibilität und gesparten Kosten erfreut.

SQL Link bringt in diesem Kontext auch nochmal einen Qualitätsschub. Wenn man z.B. Migrationsskripte für einen Bounded Context mit 15 Tabellen pflegen muss, dann tut das nicht weh. Wenn ich mich dazu im Vergleich an Systeme mit hunderten von Tabellen erinnere und was für eine Komplexität in der sauberen Migration solch dicker Datenbanken steckte…

Kurz: Microservices-Konzepte gut. Mit Verstand adaptieren. Composite DB kann ein pragmatischer Mittelweg sein.