Die Cloud aus Sicht eines Enterprise Entwicklers

Daniel Rosowski
5 min readJul 16, 2018

--

Jeder Enterprise Entwickler kennt das. Wenn man nicht aufpasst, gerät man in einen Dornröschenschlaf, von dem man so schnell nicht wieder erwacht. Bei dem Gift, in dem die Nadel getränkt ist, handelt es sich um einen Cocktail aus Compliance, Industriestandards und innovationsfeindlicher Unternehmenskultur. zZz

© Wikipedia

Es können schonmal gut und gerne 10 Jahre vergehen, ehe man aus dem Dornröschenschlaf erwacht. Wenn man denn erwacht. Und in der Zwischenzeit ist viel passiert und es kursieren Themen wie Blockchain oder Cloud und man versteht die Welt nicht mehr. So oder ähnlich ging es mir, als ich mich vor einiger Zeit dem Thema Cloud zugewandt habe. Noch schwer begeistert von der Einfachheit von RMI und JMS, glich es einer Katharsis als ich von Konzepten wie Lambda Funktionen oder AWS SQS gehört habe. (Leicht überspitzt für den dramaturgischen Effekt. :-)

Aber eins nach dem anderen. Als erfahrener Software Architekt und langjähriger Enterprise Entwickler nähert man sich solch einem Thema natürlich mit einer gesunden Portion Skepsis. Das, was wir jahrelang in mühevoller Handarbeit gemacht haben, soll heutzutage einfach so Commodity sein? Ha, das ich nicht lache! Aber ich sollte eines Besseren belehrt werden. Wir wollen uns dem Cloud Thema anhand einer Beispielanwendung nähern: Wecky — der Website Checker. Die Domäne ist denkbar einfach. Ein Benutzer kann eine Webseite angeben, die in einem vorher definierten Intervall auf Änderungen geprüft wird. Hat sich die Seite geändert, soll dem Benutzer ein Screenshot mit der geänderten Webseite zugeschickt werden.

Wecky Domäne

Natürlich haben wir auch ein paar nicht-fachliche Anforderungen an unsere Software. Das System sollte in der Lage sein

  • viele Webseiten auf einmal zu prüfen (Skalierbarkeit)
  • nur die Ressourcen zu verbrauchen, die es benötigt (Elastizität)
  • Fehlertolerant auf nicht verfügbare Services reagieren (Resilienz)

Und das soll für unsere Demozwecke auch erst einmal genügen. Los gehts!

Im ersten Schritt überlegen wir uns eine grobe Architektur, wie unsere Anwendung aussehen soll. Wir brauchen auf jeden Fall ein Backend, das über eine Web Oberfläche verfügt, mit der die Benutzer ihre Webseiten pflegen können, die in regelmäßigen Abständen geprüft werden sollen. Check.

Als nächstes folgt das regelmäßige Abrufen (Crawlen) der Webseite, ob sich was geändert hat. Als alter (naja) Enterprise Entwickler, wäre mein erster Impuls, meinem Backend einen Quartz Scheduler zu verpassen. Dann müsste ich mir überlegen, mit welcher Last ich rechnen muss, also wieviele Benutzer wieviele Webseiten überprüfen werden. Wenn ich mit meiner Schätzung

  • über den tatsächlichen Werten liege, verschwende ich Ressourcen,
  • Wenn meine Schätzung hingegen da drunter liegt, kann meine Anwendung nicht alle Webseiten überprüfen und reagiert im schlimmsten Fall nicht mehr.

D.h. die Punkte Skalierbarkeit und Elastizität sind nicht erfüllt. Hier kommt die Cloud ins Spiel. Wir wissen vorab nicht, wieviele Benutzer wir für wecky erwarten und wieviele Webseiten regelmäßig überprüft werden müssen. In nicht allzu ferner Vergangenheit war die Antwort das automatische Hochskalieren von Rechner-Ressourcen, z.B. durch den Einsatz von virtuellen Maschinen. Das löst zwar das Problem, aber richtig effizient sind wir damit trotzdem nicht, weil immer ein kompletter Server hochgefahren werden muss. Besserung verspricht der Einsatz von Containern z.B. durch Docker. Bei Containern handelt es sich um eine Virtualisierung auf Basis des Betriebssystems, weshalb es möglich wird noch kleinere Images noch schneller bereit zu stellen[1]. Bei unserem mini Usecase ist aber selbst das noch ein wenig mit Kanonen auf Spatzen geschossen. Der nächste logische Schritt ist die Bereitstellung der gesamten Laufzeitumgebung, also einer Node.js oder Python Installation, oder eben einer JVM. Diese Abstraktion nennt sich bei AWS Lambda Funktion.

Kosten und Auslastung in der Cloud

Hier verlassen wir die Management-taugliche Ebene und es wird ein wenig technischer. Achtung: Es wird auch ein wenig Code gezeigt!

Im Folgenden wollen wir uns ansehen, wie wir unsere Anwendung geschnitten haben, damit wir unsere nicht-fachlichen Anforderungen mit den Mitteln der AWS Cloud erfüllen können. Bevor ich auf die Dienste im Einzelnen eingehe, werde ich die Gesamtarchitektur kurz skizzieren.

Wecky Architektur

Unsere Anwendung besteht jetzt nicht mehr nur aus einem großen Backend, sondern aus mehreren kleinen Komponenten. Als Ausgangspunkt gibt es aber immer noch ein Backend mit Web-Oberfläche, wecky-web. Hier werden neue Benutzer angelegt und die Benutzer können Webseiten hinzufügen, die regelmäßig überprüft werden. Die Daten speichern wir in dem Amazon-eigenen KeyValue Store, der DynamoDB. Für jede Webseite die überprüft werden soll, ruft wecky-web in regelmäßigen Abständen die Lambda Funktion wecky-crawl auf, die jene Webseite auf Änderungen überprüft. Die Funktion überprüft anhand des gehashten Inhalts, ob sich die Webseite geändert hat und schreibt in diesem Fall den neuen Hashwert in die Datenbank.

AWS bietet die Möglichkeit verschiedene Trigger für eine Lambda Funktion zu konfigurieren, u.a. Änderungen in einer Tabelle in der DynamoDB oder wenn sich ein S3 Bucket (Datenspeicher) verändert. Für unser Beispiel, haben wir wecky-capture so konfiguriert, dass die Funktion für jeden neuen Hashwert aufgerufen wird und ein Screenshot der betreffenden Seite in einem S3 Bucket speichert. Der neue Screenshot wiederum dient dann im nächsten Schritt als Trigger für wecky-notify. Dem Benutzer wird über SES eine E-Mail mit einer Benachrichtigung über die Änderung, inklusive Screenshot zugeschickt.

Die Integration von AWS Lambda in unser Spring Boot Projekt (wecky-web) ist denkbar einfach (Achtung, Kotlin Code! :-). Die Annotation @LambdaFunktion kapselt den gesamten Client-Code, der notwendig ist, um unsere Lambda Funktion aufzurufen. Die Zugangsdaten für unser AWS Konto werden über Umgebungsvariablen oder in der application.properties definiert.

Sehen wir noch einmal kritisch auf unsere nicht-fachlichen Anforderungen, sind diese ebenfalls erfüllt. Unsere Architektur ist

  • Ressourcen- (und damit auch Geldbeutel) schonend, da die Lambda Funktionen nur Kosten verursachen wenn sie aufgerufen werden,
  • Skalierend, weil wir die Anzahl der Instanzen der einzelnen Lambda Funktionen nicht vorher festlegen müssen,
  • Fehlertolerant, da die Lambda Funktionen bei einem Fehler erneut ausgeführt werden, dieses Verhalten aber konfigurierbar ist.

Ein schlauer Mensch hat mal gesagt, dass die Fertigungstiefe heutzutage nicht mehr nur durch den Kauf von Standardsoftware reduziert wird, sondern auch durch den Einsatz fertiger Komponenten aus der Cloud [2]. Dieser Einschätzung kann ich nur zustimmen, wenn ich sehe, wie schnell und einfach die Entwicklung sein kann, wenn man nicht durch Commodity und boilerplate Code aufgehalten wird. Betrieb, Konfiguration und Anbindung ganzer Middleware Komponenten wie z.B. Messaging (SQS, SNS) oder Storage (S3) fallen weg und die Entwickler können sich somit auf die eigentliche Businesslogik konzentrieren. Aber auch der Betrieb erfährt eine Entlastung und kann sich ebenfalls um die reibungslose Zusammenarbeit der verschiedenen Komponenten kümmern, anstatt mit einzelnen Systemen kämpfen zu müssen.

Ganz nebenbei wird durch den Einsatz von serverless Technologie auch gegen klare Schnittstellen (z.B. Events) programmiert und dadurch eine modulare Architektur unterstützt. Was natürlich nicht heißen soll, dass es durch die Cloud automatisch nur noch sauber gekapselte Systeme geben wird. Sicher nicht. :-)

https://www.smartsquare.de

[1]: https://jaxenter.de/docker-vs-vm-54816

[2]: https://microservices-summit.de/blog/interview-mit-uwe-friedrichsen-zum-thema-resilient-software-design/

--

--

Daniel Rosowski

Programmierender Softwarearchitekt und Geschäftsführer der Smartsquare GmbH aus Bielefeld. www.smartsquare.de