2024-07-22 | Benedikt Hunger | 4 min read
Querschnittskonzepte für Microservice-Architekturen - Teil 2
Im ersten Blogpost zu den Querschnittskonzepten von Microservice-Architekturen haben wir euch die Eigenschaften von Microservices vorgestellt und welchen Herausforderungen sie trotzen. Im zweiten Teil gehen wir auf konkrete Beispiele ein, wie Querschnittskonzepte für Microservices umgesetzt werden können.
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.
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.
Scandiolife auf Instagram.
Connecte dich auf LinkedIn mit uns.
Hier zwitschert die Scandio auf Twitter.