Cloud-Infrastruktur
Damit Microservices klein genug bleiben, um diesen Namen zu verdienen, muss es einfach sein, neue Microservices zu erstellen. Zusätzlich zu der Code-Basis ist dafür einige Infrastruktur notwendig, die sich über verschiedene Services hinweg im Prinzip wenig unterscheidet.
Es ist daher sinnvoll, diese wiederkehrenden Elemente von einem dedizierten Infrastruktur-Team verwalten und warten zu lassen. Dazu gehören folgende Elemente:
Bereitstellung von Rechenressourcen
Um Ressourcen gut nutzen zu können, hat sich im letzten Jahrzehnt Container-Technologie als gewinnbringendes Konzept herausgestellt. Hierbei werden einzelne Prozesse durch Linux-Kernel-Features voneinander abgekapselt, was eine gemeinsame Nutzung von Rechenressourcen durch voneinander unabhängige Prozesse erleichtert. Wesentlich für die Nutzung von Container-Technologie ist, dass einzelne Container jederzeit (etwa auf einem anderen Rechner) neu gestartet werden können, da so eine orchestrierte hohe Auslastung der verfügbaren Rechenzeit erreicht wird. Der de-facto-Standard für die Orchestrierung von Containern ist das Open-Source-System Kubernetes, das bei guter Konfiguration eine Schnittstelle für Entwickler zum einfachen Deployment von Containern (und anderen Ressourcen) bereitstellt.
Da eine gute Konfiguration eines Kubernetes-Clusters eine relativ komplexe Aufgabe ist, sollte hierfür ein spezialisiertes Team etabliert werden, dass sich unter anderem mit der Netzwerkarchitektur, Kommunikation zwischen Containern, Secret Management und grundlegendem Logging und Monitoring in Zusammenhang mit Kubernetes beschäftigt.
Netzwerk-Konnektivität
Die innere Einfachheit von Microservices wird dadurch erkauft, dass viel Komplexität in die Kommunikation zwischen Services verlagert wird. Dafür ist es wichtig, dass Microservices eine Netzwerkverbindung zueinander und in Richtung Internet aufbauen können. Die Verbindung sollte automatisch durch mTLS abgesichert werden. Diese Automatisierung kann am besten auch durch ein zentrales Infrastruktur-Team gewährleistet werden.
Auch grundlegende Allow-Lists für den Zugriff auf Services sollten durch die Microservice-Teams einfach eingerichtet werden können, und gegebenenfalls sollten aus Compliance-Gründen manche Netzwerkregeln durch das Infrastruktur-Team verbindlich festgesetzt werden. Die Kommunikation zwischen Microservices ist erheblich leichter zu erreichen, wenn die Infrastruktur bei einem einzelnen Cloud-Provider gehostet wird.
Persistenz
Microservice-Container sollten jederzeit neu gestartet werden können, ohne Daten zu verlieren. Das impliziert, dass persistente Datenhaltung außerhalb der Microservices stattfinden muss, typischerweise in Datenbanken oder in persistenten Volumes. Neben allgemeinen Schwierigkeiten wie Authentifizierung und Autorisierung, sowie der Konnektivität zu den Datenhaltungssystemen bestehen hier spezialisierte Herausforderungen wie die Erstellung von Daten-Backups und Snapshots, um die Wiederherstellbarkeit persistenter Daten gewährleisten zu können.
Für verschiedene Bedürfnisse sollten verschiedene Typen von Datenbanken zur Verfügung gestellt werden, aus denen Microservice-Teams auswählen können: etwa eine SQL-Datenbank, eine Dokumentendatenbank und ein Cache-System. Das ist wichtig, um die Technologieoffenheit bei der Umsetzung von Microservices zu gewährleisten, sodass die Microservice-Teams die beste Technologie für ihren Anwendungsfall auswählen können.
Die Bereitstellung von Datenbanken oder Volumes sollte möglichst automatisiert erfolgen, wofür eine enge Zusammenarbeit mit dem Kubernetes-Team notwendig ist.
Wir planen Ihre Microservice-Architektur. Und bieten noch so viel mehr im Bereich agile Softwareentwicklung. Überzeugen Sie sich selbst.
Logging und Monitoring
Um Fehlerfälle reproduzieren und beheben zu können, ist es entscheidend, dass es einen einfachen Weg gibt, um auf die produzierten Logs der einzelnen Microservices zugreifen zu können. Hierfür ist der Industriestandard ein Elastic Stack, der bestenfalls von einem zentralen Team gehosted und gemanaged wird, damit die Microservice-Teams sich nicht um das Setup von Logging-Infrastruktur kümmern müssen. Auch andere Lösungen als ein Elastic Stack sind hier denkbar, doch eine Standardlösung sollte zentral vorgegeben werden, und auch das Log-Format (beispielsweise JSON mit bestimmten vorgegebenen Feldern) sollte über Microservices hinweg standardisiert sein.
Logs müssen auch über mehrere Services hinweg miteinander verknüpft werden können, insbesondere auch über REST-Requests oder asynchrones Messaging hinweg. Hierfür ist Request Tracing via OpenTelemetry geeignet, indem die Traces über Requests hinweg propagiert werden, beispielsweise mit Hilfe der B3-Spezifikation. Zusätzlich können die so entstehenden Traces natürlich dafür genutzt werden, Bottlenecks bei Requests zu erkennen und zu beheben.
Auch ein Monitoring-/Alerting-Stack (typischerweise mit Hilfe von Prometheus und Grafana) sollte zentral maintained sein und mit standardisierten Metriken sowie individuell konfigurierbaren Metriken gefüllt werden können. Alerts sollten individuell durch die Microservice-Teams einstellbar sein.
API-Design
Je nach Microservice können die Anforderungen an die APIs zur Kommunikation mit dem Microservice sehr unterschiedlich sein. Dennoch kann es sinnvoll sein, gemeinsame Anforderungen an die API-Struktur (beispielsweise HATEOAS oder gRPC) zu stellen, die nur in begründeten Ausnahmefällen nicht berücksichtigt werden. Für HTTP-APIs kann OpenAPI eine gute Lösung für die Dokumentation darstellen.
Gegebenenfalls kann man sich dafür entscheiden, die Bereitstellung von OpenAPI-Spezifikationen für Microservices verpflichtend zu gestalten, sodass sich die Entwickler von Clients auf die Existenz dieser Spezifikationen verlassen können. In jedem Fall sollte ein gemeinsames Schema für die Dokumentation von APIs (inklusive Fehlerfällen) geschaffen werden, damit es einfacher wird, relevante Dokumentation zu finden.
Messaging
Asynchrone Kommunikation über Messaging-Systeme kann wesentlich dabei helfen, das Gesamtsystem resilient zu gestalten. Die durch die Asynchronität entstehende temporäre Inkonsistenz bei der Datenhaltung wird bewusst in Kauf genommen („Eventual Consistency“), um schnellere Requests und eine Entkopplung verschiedener Microservices zu erreichen.
Damit Kommunikation über Messaging zwischen verschiedenen Microservices funktioniert, sollte das Messaging-System selbst von einem zentralen Team bereitgestellt und verwaltet werden. Das Format der Messages sollte wie bei den APIs mithilfe eines gemeinsamen Schemas dokumentiert werden.
Authentifizierung und Autorisierung
Authentifizierung und Autorisierung sind zentrale Aufgaben, die nicht von einzelnen Microservice-Teams erledigt werden können. Hierfür sollte eine zentrale Lösung, beispielsweise basierend auf OpenID, bereitgestellt werden.
Zusammenfassung
Eine Microservice-Architektur kann gerade für komplexe Systeme eine gute Lösung sein, um schnell Verbesserungen am System sowie neue Features zu implementieren. Dadurch entstehen allerdings Abhängigkeiten zwischen Microservices und somit auch zwischen den Microservice-Teams.
Die hier beschriebenen Querschnittskonzepte helfen dabei, Konsistenz, Sicherheit und Effizienz in einem Microservice-Umfeld sicherzustellen.
Kontakt
Region

Sie möchten mehr erfahren oder haben Sie eine Frage? Dann treten Sie mit uns in Kontakt!
Microservices sind ein Design-Pattern in der Softwarearchitektur, das zum Ziel hat, durch kleinere Teams und konzentriertere Verantwortlichkeiten Kommunikationswege zu verkürzen und so zu einer geringeren Time-to-market zu gelangen.
Die grundlegenden Ideen von Microservices gehen auf die Unix-Prinzipien zurück, die bereits 1978 von Doug McIlroy formuliert wurden. Laut ihm sollten Programme so gestaltet werden, dass sie:
- genau eine Aufgabe haben und diese dafür gut erfüllen,
- hintereinander geschachtelt werden können, sodass ein Programm die Eingabe für ein anderes Programm produziert,
- früh getestet und gegebenenfalls wieder aufgegeben werden können,
- Tools für wiederkehrende Aufgaben bei der Entwicklung nutzen.
Microservices werden durch die folgenden Eigenschaften charakterisiert:
- Single Purpose: Wie bei den Unix-Prinzipien sollte ein Microservice genau eine Aufgabe gut erfüllen.
- Encapsulation: Microservices haben das alleinige Eigentum an ihren Daten. Sie interagieren mit der Außenwelt über wohldefinierte Schnittstellen.
- Ownership: Ein einzelnes Team (bestenfalls bestehend aus 5-9 Personen) ist verantwortlich für einen Microservice über seine gesamte Lebenszeit.
- Autonomy: Das für den Microservice zuständige Team darf ohne Absprache zu jeder Zeit den Microservice bauen und deployen. Das Team ist frei in Implementationsentscheidungen.
- Multiple Versions: Es ist möglich, dass zur gleichen Zeit verschiedene Versionen eines Microservices existieren.
- Choreography: Es gibt kein zentralisiertes System, das einen Workflow orchestriert. Stattdessen ist jeder Microservice in der Lage sich selbstständig mit den Informationen zu versorgen, die er für seine Funktionalität braucht.
- Eventual consistency: Eine kurzzeitige Inkonsistenz von Daten zwischen Microservices ist akzeptiert, solange die Daten schließlich wieder konsistent werden.
Herausforderungen von Microservices
Microservices sind durch ihre innere Einfachheit generell besser skalierbar und leichter und schneller zu ändern als Monolithen, in denen die gesamte Logik in einem einzelnen Programm enthalten ist. Durch die kleinen Teams fühlen sich (und sind) Microservice-Teams deutlich stärker für den Erfolg ihrer Microservices verantwortlich, was häufig zu besseren Ergebnissen und Entscheidungen führt.
Microservices erleichtern Omnichannel-Lösungen durch geteilte Backend-Funktionalität, die von verschiedenen Benutzerschnittstellen konsumiert werden können.
Erhöhte Komplexität
Auf der Ebene einzelner Microservices schaffen wir uns durch den begrenzten Aufgabenbereich und die Kapselung eine einfache und schöne Welt, doch TANSTAAFL!³ Die innere Einfachheit von Microservices wird erkauft durch die erhöhte Komplexität in Bezug auf die Kommunikation zwischen Microservices sowie eine gewisse Redundanz: Da die Microservice-Teams vollständig für ihre Services verantwortlich sind (Ownership) und sie auch selbstständig deployen können (Autonomy), müssen sie technisch dazu in der Lage sein, dieses Deployment tatsächlich durchzuführen. Das schließt sowohl Kompetenzen in Bezug auf Cloud-Infrastruktur ein als auch die Ressourcen, die für den Betrieb der Infrastruktur notwendig sind.
Konkreter können wir uns einen Mailing-Service vorstellen, der dafür zuständig ist, Informationsmails über ein Produkt an Kunden zu versenden. Der Service muss im Laufe der Entwicklung gebaut und dann auch ausgeführt werden. Die dafür verwendeten Computer müssen die notwendige Konnektivität haben, um diese Aufgaben durchzuführen. Sobald der Service läuft, müssen andere Services dazu in der Lage sein, den E-Mail-Prozess in Gang zu setzen. Mögliche Wege hierfür sind beispielsweise ein Event-System, aus dem der Mailing-Service selbstständig (im Sinne der Eigenschaft Choreography) die für ihn relevanten Events herausfiltert und zu E-Mails weiterverarbeitet.
So ein Event-System oder Messaging-System muss aber zum einen bereitgestellt werden und zum anderen von verschiedenen Teams mit ihren jeweiligen Microservices genutzt werden können. Ein anderes denkbares Szenario wäre die Ansprache des Mailing-Services via REST-Schnittstelle. In diesem Fall muss der Client dazu in der Lage sein, über ein Netzwerk mit unserem Mailing-Service zu kommunizieren, und diese Verbindung muss so abgesichert sein, dass nur autorisierte Services Zugriff auf die Schnittstelle bekommen.
Wir planen Ihre Microservice-Architektur. Und bieten noch so viel mehr im Bereich agile Softwareentwicklung. Überzeugen Sie sich selbst.
Authentifizierung & Autorisierung
Authentifizierung und Autorisierung ist typischerweise ein relativ komplexes Problem und sollte innerhalb des Unternehmens auch konsistent gehandhabt werden, um die Nachvollziehbarkeit zu erhöhen. Daher ist es empfehlenswert, wenn Microservice-Teams sich nicht eigenständig für dieses Thema verantwortlich sind.
Da zum einen mehrere Instanzen des Mailing-Service in gegebenenfalls verschiedenen Versionen koexistieren können (Multiple Versions) und zum anderen Microservice-Instanzen jederzeit neu deployed und insbesondere auch gestoppt werden können (Autonomy), ist es essenziell, dass relevante Daten (wie beispielsweise fertig zusammengestellte Mails, die noch nicht versendet werden konnten) instanzübergreifend und permanent gespeichert werden. Dafür sind Datenbanken und persistente Volumes nötig, die bereitgestellt und gewartet werden müssen. Auch Backups und Snapshots der Daten sollten existieren und regelmäßig getestet werden.
Für besondere Herausforderungen sorgt der Fehlerfall: Wenn irgendein Prozess im Gesamtsystem plötzlich nicht mehr funktioniert, ist es wichtig, über mehrere Microservices hinweg Fehleranalyse betreiben zu können. Hierfür ist eine konsistente Logging-Infrastruktur sowie Request Tracing und Alerting hilfreich. Natürlich muss auch für diese Lösungen Infrastruktur bereitgestellt werden.
Zusammenfassung
Die beschriebenen Herausforderungen zeigen, dass es einige Punkte gibt, an denen wir serviceübergreifend für Einheitlichkeit sorgen sollten. Manche dieser Punkte werden wir in diesem Artikel genauer unter die Lupe nehmen. Elemente der Softwarearchitektur, die (potenziell) für mehrere Bausteine der Architektur (in unserem konkreten Fall also Microservices) relevant sind, nennt man Querschnittskonzepte.
Um Redundanz zu vermeiden, sollten solche Querschnittskonzepte in der übergreifenden Architekturdokumentation behandelt werden, unabhängig von den einzelnen Komponenten. Es ist wichtig, Querschnittskonzepte frühzeitig festzulegen, da eine Migration zu einem späteren Zeit viel Kapazität über alle Teams hinweg in Anspruch nimmt.
Coming up
Im nächsten Beitrag gehen wir auf die Basisbausteine von Microservices ein, die sich nur wenig unterscheiden und daher zentral von einem Infrastrukturteam verwalten werden können.
Kontakt
Region

Sie möchten mehr erfahren oder haben eine Frage? Dann treten Sie mit uns in Kontakt!