Inhalt
In früheren Teilen dieser Serie haben wir grundlegende Schritte zur Einrichtung eines serverlosen Projekts untersucht, einschließlich der Einrichtung einer Entwicklungsumgebung mit Emulationstools und der Skizzierung einer allgemeinen mehrstufigen Architektur. Dieser Abschnitt konzentriert sich auf die Implementierung von Entwurfsmustern, die speziell für die Entwicklung eines serverlosen Systems nach dem Paradigma Function as a Microservice (FaaM) zugeschnitten sind. \n\nDie Frage der Servicegranularität hat sich parallel zur Geschichte der verteilten Datenverarbeitung entwickelt. In den 1970er und 80er Jahren entstanden frühe Integrationsansätze wie Remote Procedure Calls (RPC), CORBA und Distributed Computing Environment (DCE), die jedoch oft in Skalierbarkeit und Flexibilität für hybride Umgebungen eingeschränkt waren. Mitte der 1990er Jahre markierte die Einführung der Serviceorientierten Architektur (SOA) einen Wendepunkt, die bis Anfang der 2000er Jahre durch SOAP-basierte Implementierungen an Bedeutung gewann. SOA revolutionierte das Softwaredesign durch die Ermöglichung lose gekoppelter Dienste. Die Entwicklung setzte sich in den 2010er Jahren mit REST, ereignisgesteuerten Architekturen (EDA) und Microservices fort, doch eine anhaltende Herausforderung bleibt: die Bestimmung der idealen Größe und des Umfangs eines Dienstes.\n\nHistorisch definierte SOA zwei Haupttypen der Servicegranularität: grobkörnig und feinkörnig. Grobkörnige Dienste umfassen breite Geschäftsfähigkeiten, während feinkörnige Dienste sich auf eng gefasste Funktionen konzentrieren. Beide Extreme bergen Herausforderungen; große grobkörnige Dienste laufen Gefahr, unhandliche "Monolithen" zu werden, während feinkörnige Dienste eine überwältigende Anzahl kleiner, voneinander abhängiger Komponenten erzeugen können, was Skalierbarkeit, Änderbarkeit und Sicherheit erschwert. Das Service-Oriented Modeling Framework (SOMF) bietet differenzierte Kategorien: Atomare Dienste sind grundlegende, unteilbare Komponenten mit begrenzten Prozessen; Komposite Dienste aggregieren atomare oder andere komposite Dienste in hierarchischen Strukturen; und Cluster sind Gruppen verwandter Dienste, die zusammen an umfassenderen Lösungen arbeiten.\n\nDie Übertragung dieser Konzepte in den Bereich des serverlosen Rechnens mit Serverless Framework und AWS Lambda erfordert das Verständnis von drei zentralen Konstrukten: Ereignisse, Funktionen und Dienste. Ereignisse lösen Funktionen aus, die diskrete Codeabschnitte ausführen, um spezifische Aufgaben zu erfüllen. Dienste kapseln Gruppen von Lambda-Funktionen zusammen mit ihren auslösenden Ereignissen und Infrastrukturanforderungen. Das Serverless Framework empfiehlt typischerweise, für jede CRUD-Operation einzelne Lambda-Funktionen zu erstellen – was bedeutet, dass eine Entität wie Benutzer vier Lambda-Funktionen entsprechen könnte. Obwohl dies einfach ist, skaliert dieser Ansatz schlecht: Zehn Entitäten führen zu 40 Funktionen, die jeweils verwaltet werden müssen und mit separaten AWS API Gateway-Instanzen verbunden sind, was den Verwaltungsaufwand erhöht.\n\nUm diese Komplexität zu bewältigen, wird das Function as a Microservice (FaaM)-Muster vorgeschlagen. Hier fungiert jede Lambda-Funktion als kleiner Cluster, der mehrere verwandte Geschäftsfähigkeiten verwaltet und verschiedene atomare Ereignisse intern weiterleitet. Beispielsweise verwaltet eine Geolokalisierungsfunktion CRUD-Operationen für Länder, Städte und Regionen gemeinsam, anstatt für jede Städteoperation eine eigene Funktion zu haben. Um monolithische Überlastung zu vermeiden, sollte jede Funktion idealerweise nicht mehr als 7±2 Entitäten verwalten, entsprechend den kognitiven Grenzen, die durch Millers Gesetz beschrieben werden. Dieses Design setzt voraus, dass jede Funktion die alleinige Verantwortung für ihre spezifische Datenquelle trägt.\n\nDie Implementierung von FaaM innerhalb von AWS Lambda erfordert effiziente Routing-Mechanismen, da jede Lambda-Funktion nur einen einzigen Einstiegspunkt-Handler hat. Ein Client-Dispatcher-Server-Muster kann dies erleichtern, indem eingehende Anfragen basierend auf ihren URI-Pfaden weitergeleitet werden. Beispielsweise sollte eine HTTP-Anfrage an /movie an die relevante Funktion weitergeleitet werden, die filmbezogene Operationen verarbeitet. Mit diesem Muster können mehrere logische Dienste – wie Benutzer, Geolokalisierung und Beiträge – denselben Handler-Code teilen, aber die Verarbeitung intern durch Routing differenzieren. Dieser Ansatz reduziert die Anzahl der Lambda-Funktionen und API-Gateway-Endpunkte, vereinfacht die Verwaltung und bewahrt gleichzeitig klare Geschäftsdomänengrenzen.\n\nIn der Praxis könnte die Serverless Framework-Konfiguration mehrere Dienste mit mehreren HTTP-Ereignissen definieren, die alle auf denselben Handler verweisen – beispielsweise Login-, Logout- und Signup-Endpunkte unter Benutzern, verschiedene Standortendpunkte unter Geolokalisierung und CRUD-Operationen für Filme unter Beiträgen. Die Routing-Logik im gemeinsamen Handler prüft die URI und Methode des Ereignisses, um das entsprechende Geschäftslogikmodul aufzurufen. Diese Strategie verbessert die Wartbarkeit, indem sie redundanten Handler-Code vermeidet, und ermöglicht ein modulares Wachstum innerhalb serverloser Architekturen.