Dieser Post beschäftigt sich nicht mit dem Thema Serverless an sich. Dies wurde bereits von Kollegen in früheren Beiträgen erläutert. Es wird hier konkret auf das Thema Vendor-Lock-in eingegangen. Wer das als Problem für die Entwicklung von Serverless-Systemen betrachtet, kann durch den Einsatz bekannter Pattern in den einzelnen Serverless-Components für Entspannung sorgen.

Serverless und Vendor-Lock-in

Für einfache Funktionen, die von Zeit zu Zeit kleine Arbeiten (z.B. Reaktion auf Warnings beim Monitoring) oder banale Dinge erledigen, ist der Aspekt des Vendor-Lock-in nicht kritisch. Jedoch können Serverless-Components auch für extrem skalierbare Business-Cases (englisch: “scale out”) verwendet werden. Die Fähigkeit dazu wird durch die Entkoppelung von der tatsächlichen Laufzeit-Infrastruktur (z.B. Web-Server, Application-Server, Load-Balancer, Netzwerk-Komponenten) gewährleistet. Jedoch ist die Abhängigkeit der einzelnen Komponenten zu den umliegenden Diensten sehr hoch, welche nicht-funktionale Funktionalität (z.B. HTTP-API, Datenbank) zur Verfügung stellen. Diese müssen im gleichen Umfang skalieren, wie die Serverless-Components selbst.

In Cloud-Umgebungen werden diese Dienste von den Anbietern selbst als Managed Services (z.B. AWS ApiGateway, DynamoDB etc.) bereitgestellt. Die Nutzung dieser Services ergibt strategisch Sinn, da es nicht zielführend ist, eine extrem skalierbare Anwendung an eine schwer skalierbare relationale Datenbank zu binden. Bei On-Premise betriebenen Serverless-Systemen (z.B. mit Kubeless) gibt es ähnliche, wenngleich nicht so einseitig Anbieter-bezogene, Abhängigkeiten zu den umliegenden Diensten, da hier ebenfalls die erforderliche Skalierung durch das dahinter liegende Produkt gewährleistet sein muss.

Gegenüber traditionellen Anwendungen ist diese Abhängigkeit zur Umgebung sehr ähnlich. Soll eine derartige Anwendung ebenfalls skalieren können, muss dies das Umfeld im gleichen Maß können. Ist die Anwendung für den On-Premise-Betrieb gedacht, ist ein hohes Investment in den Betrieb notwendig, um sowohl die benötigten Hardware-Komponenten als auch die benötigten Produkte betreiben zu können - dazu zählen auch entsprechendes Know-How, Support, Wartungsverträge etc. Daraus folgt unweigerlich neben dem technischen Vendor-Lock-in auch ein monetärer Vendor-Lock-in. Soll die Anwendung in der Cloud betrieben werden, wird das Investment in die Umgebung durch das Verwenden von Cloud-Diensten deutlich geringer, jedoch gibt es hier den gleichen Grad an technischem Vendor-Lock-in wie bei Serverless-Systemen. Somit unterscheiden sich Serverless-Systeme in diesem Punkt kaum von traditionellen Anwendungen.

Bei Serverless-Systemen in der Cloud ist zwar der Vendor-Lock-in an den Anbieter etwas größer, auf lange Sicht gesehen ist jedoch das ersparte Investment in die Laufzeit-Infrastruktur größer als das Investment, welches eventuell an Tag X in der Zukunft benötigt wird, um von einem Cloud-Anbieter zum Nächsten (oder On-Premise) zu wechseln.

Serverless-Components: Mehr als eine Funktion

Oft wird mit Serverless nur die Ausführung einzelner Funktionen (ähnlich einer Method) assoziiert (FaaS). Tatsächlich kann hinter dieser Funktion eine normale Anwendung stehen. Um diese Abgrenzung zu verdeutlichen, werden in diesem Post Serveless-Components und Serverless-Systems als Alias für beliebig komplexe, serverlose Anwendungen verwendet. Eine serverlose Anwendung (Serverless-System) besteht dabei aus einer Kombination unterschiedlicher Serverless-Components und nicht-funktionaler Diensten.

Die folgende Grafik zeigt einen beispielhaften Aufbau eines Serverless-Systems auf Basis von AWS.

Das AWS Lambda soll nun verschiedene HTTP-Anfragen beantworten, um Daten aus der DynamoDB per HTML anzuzeigen. Die fachliche Funktion im AWS Lambda ist direkt vom ApiGateway und der DynamoDB abhängig und kann - von außen betrachtet - nur in AWS betrieben werden.

Wird jedoch der innere Aufbau dieser Serverless-Component betrachtet, zeigt sich, dass sich die Abhängigkeit zu AWS lediglich an zwei Stellen befindet: Die erste Stelle ist der Aufruf durch das ApiGateway, die zweite der Aufruf von DynamoDB.

Pattern erkannt?

Es handelt sich hier um Dependency Injection. Richtig, nichts Neues also. Serverless-Components lassen sich sehr schön nach diesem Pattern implementieren. Je nach verwendeter Programmiersprache besser oder schlechter, auch ohne Spring.

Dependency Injection ist hier nur ein Beispiel. Es kann jedes Pattern angewandt werden, mit dem bisher auch die tatsächliche Implementierung von der Nutzung entkoppelt wird. Stichwort: lose Kopplung.

Neben der Beschränkung des Vendor-Lock-in auf wenige Stellen, bietet diese Struktur die Möglichkeit, die fachliche Funktion der Serverless-Component ohne Laufzeit-Infrastruktur entwickeln und testen zu können[1].

In traditionellen Anwendungen wurde diese lose Kopplung unter anderem durch den Einsatz von Frameworks (z.B. Spring, JPA etc.) erreicht. Jedoch zeigt sich auch hier, dass es nicht komplett unabhängig geht. Ein Beispiel:
Würde man eine einfache Web-Anwendung mit Java, wie in dem Lambda-Beispiel, ohne den Einsatz von zusätzlichen Frameworks entwickeln, welche ebenfalls lose gekoppelt sein soll, würde eine sehr ähnliche Struktur entstehen. Anstatt der DynamoDB würde eine Relationale Datenbank zum Einsatz kommen, welche sich auf SQL als einheitliches Interface bezieht. Jedoch hat jedes implementierende Produkt seine eigenen Einfluss auf das SQL Interface (z.B. PostgreSQL vs. Oracle), wodurch eine Abstraktion zwischen Business-Logik und Persistenz notwendig ist.

Fazit

Wenn Serverless-Components nach Pattern für eine lose Kopplung entwickelt werden, relativiert sich das Problem des Vendor-Lock-in auf wenige Punkte, an denen mit dem Umfeld kommuniziert wird. Der fachliche Anteil bleibt dabei neutral. Somit unterscheiden sich Anwendungen, die als Serverless-System betrieben werden, nicht viel von traditionellen Anwendungen. Der Vendor-Lock-in beschränkt sich dabei auf die gleichen Punkte wie bei jeder Anwendung, welche von umliegenden Systemen abhängig ist.

  1. AWS hat vor kurzem Amazon DynamoDB lokal für Testzwecke bereitgestellt.  ↩