Blog Microservices vs. μServices

Microservices vs. μServices

Microservices vs. μServices -- Was bleibt für die Softwarearchitektur?

Microservices oder μServices

Seit einiger Zeit erlangt der Begriff Microservice größere Aufmerksamkeit. Viele Blogbeiträge und Artikel in Fachzeitschriften sowie Vorträge auf Konferenzen und Podcasts beschäftigten sich mit dem Thema. Da wir bei n-design seit Jahren Produkte auf der Basis von OSGi entwickeln, war mir der Begriff im OSGi-Kontext sehr vertraut. Schnell war aber klar, dass sich die aktuellen Beiträge zu dem Thema mit Webservices und nicht mit prozessinternen Services befassen. Letztere werden im OSGi-Kontext μServices (gesprochen Microservices) genannt. Während Peter Kriens sich einen anderen Namen für Microservices wünscht, beschäftigt mich die Frage, was man aus beiden Microservice-Welten grundsätzliches für den Architekturentwurf von Softwareprodukten lernen kann? Gibt es für vergleichbare Problemstellungen äquivalente Lösungen?

μServices in OSGi

OSGi spezifiziert ein dynamisches Komponentensystem für Java. Dadurch wird eine modulare Softwarearchitektur ermöglicht, bei der Implementierungsdetails der Module untereinander verborgen werden können. Module (im OSGi-Jargon: Bundles) können dynamisch zur Laufzeit installiert und deinstalliert werden. Dies erfordert nicht nur zur Compile-Zeit, sondern auch zur Laufzeit eine lose Kopplung zwischen den Module. Denn ein konsumiertes Modul kann ggf. nicht verfügbar sein, was einen defensiven Umgang bei der Verwendung von Services erfordert.
Daher stellen Module ihre Funktionalität über Services zur Verfügung, die sie in der Service-Registry der OSGi-Laufzeitumgebung für Konsumenten erreichbar machen. μServices in OSGi sind damit normale Java-Objekte, die in unseren Projekten häufig den Charakter von Services im Sinne des Domain Driven Design haben. D.h. sie stellen übergeordnete domänenspezfische Funktionen zur Verfügung und die Operationen sind in der Regel zustandslos. Dabei hat ein μService eine hohe Kohäsion in Bezug auf die spezifische Aufgabe des zugrundeliegenden Moduls.
Einen guten Überblick über die Verwendungsmuster von μServices gibt Peter Kriens in einem Blogbeitrag.

Microservices als Webservices

Der Grundgedanke hinter diesem Microservice-Begriff ist, Webservices weniger schwergewichtig als bisher üblich zu gestalten. Dies bezieht sich zum einen auf die Größe, also die Menge der angebotenen Operationen und damit auf die Zuständigkeit des Services. Die Abgrenzung eines Microservice wird oft mit den Grenzen eines Bounded Context im Domain Driven Design abstrakt verglichen. Zum anderen ist auch ein leichtgewichtigeres Deployment Gegenstand der Idee. Ziel ist also auch hier, eine monolithische Anwendung in Module zu strukturieren und diese per (Web-)Service erreichbar zu machen. Der fundamentale Unterschied zu den OSGi-μServices ist, dass Webservices nicht im selben Prozess und in der Regel nicht auf der gleichen Maschine ausgeführt werden. Damit wird bei dieser Microservice-Idee eine viel weitreichendere Unabhängig der Services untereinander angenommen. D.h. die Services sind in der Regel bis zur Datenbank hin vollständig autark. Auch die Technologie, mit der sie entwickelt und betrieben werden, kann theoretisch von jedem einzelnen Microservice und dessen Entwicklerteam definiert werden.
Eine gute Einführung zu dem Thema haben Martin Fowler und James Lewis verfasst.

Unterschiedliche Granularität

Ein OSGi-μService wird in der Regel eine kleinere Granularität haben als ein Microservice. Das liegt im Wesentlichen daran, dass in einem OSGi-Kontext auch Architekturschichten sinnvoll über Services miteinander verbunden werden. In unseren Projekten ist daher, z.B. die Persistenzschicht über Services erreichbar. Zusätzlich zu einer fachlichen, vertikalen Schneidung von Services ist also in OSGi-Projekten häufig auch eine horizontale Schneidung von Services zu finden. Daher ist die Zahl der Services in einer OSGi-Anwendung höher als in einer Microservice-Anwendung.

Umfassende Konzepte

Sowohl μServices als auch Microservices sind konzeptionell umfassend unterbaut. Bei den OSGi-Microservices sind diese Konzepte Bestandteil der OSGi-Spezifikationen und beinhalten vorwiegend Lösungen für die Handhabung der dynamischen Verfügbarkeit von Services. Bei den Web-Microservices sind die Konzepte weniger technologisch als vielmehr abstrakt architektonisch und organisatorisch ausgeprägt. In Bezug auf die organisatorischen Aspekte wird hier Conway's Law bemüht. Dies formuliert die These, dass das Design eines Systems, das eine Organisation entwickelt, eine Kopie der Kommunikationsstruktur dieser Organisation ist. Wird eine Software also in verschiedenen Abteilungen einer Firma entwickelt, werden sich nach dieser These die dort entwickelten Komponenten in ihrer Verantwortlichkeit an den Verantwortlichkeiten der jeweiligen Abteilungen orientieren. Da dies nicht unbedingt einem sinnvollen Zuschnitt der Module entspricht, wird für die Entwicklung eines Microservices vorgeschlagen, die Teams entlang der Services zu bilden und nicht auf vorhandenen Strukturen aufzusetzen. Wie realistisch die Umsetzung eines solchen organisatorischen Zuschnitts ist, wird stark von der jeweiligen Organisation abhängen. Die Frage ist auch vielmehr, welcher Nutzen durch eine sehr stark ausgeprägte technologische Unabhängigkeit einzelner Microservices erreicht wird. Aus meiner Sicht liegt der Hauptnutzen eines Service-orientierten Ansatzes in softwaretechnischen Aspekten.

Was bleibt aus softwaretechnischer Sicht?

Das Entwicklerleben mit Services ist nicht immer leicht. Man wird schnell Opfer ihrer dynamischen Natur, und in einem stark modularisierten System hangelt man sich nicht ohne Aufwand durch ggf. weit verteilte Abhängigkeiten. Der große Vorteil ist aber, dass Module und Abhängigkeiten klar definiert sind.

Services als Kommunikationsschnittstelle

Durch unsere OSGi-Projekte habe ich gelernt, Service-orientierte Architekturen zu entwickeln und zu schätzen. Sie bieten viele gute Eigenschaften in Bezug auf Testbarkeit, Wiederverwendbarkeit und Restrukturierung. Sie sind der wohldefinierte Ort für die Kommunikation verschiedener Module untereinander. Genau diese klaren Grenzen in einem System sind der Kern ihrer Vorteile. Zugleich besteht bei der fachlichen Definition dieser Schnittstellen die große Herausforderung darin, eine starke Kohäsion eines Services zu erzielen.

Technologieunabhängige Implementierung von Services

Diese Erkenntnis ist für beide Microservice-Konezpte gültig. Entscheidend ist, dass das Softwaredesign Service-orientiert ist. Ob Services als OSGi- μServices oder als Webservices deployt werden ist eine andere Frage. Daher plädiere ich für eine technologieunabhängige Entwicklung eines Services. Um die Testbarkeit und verschiedene Betriebsszenarien zu ermöglichen, sollte eine technologiespezfische Hülle um den Service erst in der jeweiligen technologischen Umgebung konstruiert werden.
Ein Service wird also zunächst fachlich spezifiziert und dann z.B. in Java als POJO implementiert. Diese Implementierung ist ohne spezifische technische Infrastruktur test- und wartbar. Erst bei der Integration in eine bestimmte technische Umgebung, z.B. in OSGi oder als Webserivce, wird ein entsprechender Wrapper um den Service herumgebaut oder generiert. Dabei bleibt der Service als rein domänenspezifische Implementierung unbedingt erhalten.

Service-Dynamik behandeln

Eine technische Herausforderung, die bei der Verwendung beider Service-Konzepte zu bewältigen ist, ist die Dynamik bezüglich der Service-Verfügbarkeit. Hier können beide Service-Communities ggf. voneinander lernen. Mein Eindruck ist, dass bei der Vermarktung des Themas „Microservices“ die zusätzliche, nicht unerhebliche Komplexität durch die Service-Dynamik unterschätzt wird. Häufig wird nur der Vorteil genannt, dass bei dem Ausfall eines Microservices nicht das komplette System betroffen ist. Dass der Rest der Anwendung ggf. sehr Aufwendig für die Behandlung fehlender Services fit gemacht werden muss, findet häufig keine Erwähnung. Welche Fallstricke beim Bau und Betrieb verteilter Systeme lauern können ist u.a. in „Release it!“ ausführlich beschrieben.
OSGi bietet zur Behandlung der Service-Dynamik einiges an Hilfestellungen. So können ServiceTracker verwendet werden, um Service-Konsumenten über den Zustand eines Services zu informieren. Mit Declarative Services können komfortabel Service-Abhängigkeiten beschrieben und der Lebenszyklus eines Graphen von Services kontrolliert werden. Blueprint generiert dynamische Proxies um einen konsumierten Service. Dieser Proxy beobachtet die Verfügbarkeit des Services und kann so z.B: ein Service-Update zur Laufzeit sicher gestalten.

Service-Kompatibilität berücksichtigen

In einem serviceorientierten Entwurf werden Aspekte des Dependency Managements auf eine höhere Ebene verschoben. Dies betrifft auch die Kompatibilität der Service-Schnittstellen untereinander. Während in einer monolithischen Anwendung bereits zur Compile-Zeit erkannt werden kann, dass Schnittstellen nicht mehr kompatibel sind, fällt dies in einer serviceorientierten Anwendung ggf. erst zur Laufzeit auf. In OSGi wird versucht, dies mit dem Konzept des Semantic Versioning in den Griff zu bekommen. Hierbei wird eine dreiteilige Versionsnummer verwendet. Ändert sich z.B. die erste Nummer, weiß der Client des Service, dass diese Version nicht mehr abwärtskompatibel zur vorherigen Version ist und kann darauf entsprechend reagieren.

Was bleibt?

Service-Orientierte Architekturen stellen für mich den richtigen Weg dar, immer komplexer werdende Geschäftsanwendungen zu strukturieren. Es bleibt die Erkenntnis: Eine modulare Softwarearchitektur wird am besten durch technologieunabhängiges, domänenspezifisches Service-orientiertes Design erreicht. Ob diese dann als μService oder Microservice betrieben werden, ist eine Frage die jenseits der Strukturierung der Anwendung in Services zu stellen ist.