Der einfache Weg zum Serverless Computing

Serverless Computing selbst (wörtlich "Serverless") gewann 2014 nach der Ankündigung von AWS Lambda - einer der ersten Serverless-Plattformen - große Popularität. Seitdem hat die Popularität des serverlosen Ansatzes nur zugenommen, aber die Entwicklung von Tools hält leider nicht Schritt.



Mein Name ist Vladislav Tankov, ich habe 2018-2020 beim JetBrains Corporate Master-Programm bei ITMO studiert und arbeite seit 2017 bei JetBrains .



Im Sommer 2018 versuchten einige meiner Kollegen und ich beim JetBrains-Hackathon, ein Tool für die Kotlin-Sprache zu entwickeln, das die Erstellung serverloser Anwendungen durch Analyse des Anwendungscodes vereinfacht.



Nach dem Hackathon, bereits im Rahmen der wissenschaftlichen Arbeit im Corporate Master-Programm bei JetBrains, habe ich beschlossen, die Entwicklung dieses Projekts fortzusetzen. In zwei Jahren hat das Tool die Funktionalität erheblich erweitert und erworben, aber seinen Namen beibehalten - Kotless oder Kotlin Serverless Framework.



Was ist Serverless?



Erinnern wir uns zunächst daran, woraus die einfachste Serverless-Computing-Plattform besteht. Eine solche Plattform umfasst drei Hauptkomponenten:



  • das Ausführungssystem für serverlose Funktionen - kleine Anwendungen, die bestimmte Ereignisse verarbeiten;
  • eine Reihe verschiedener Schnittstellen von der Außenwelt (oder einer Cloud-Plattform wie AWS) zum Ereignissystem der Plattform, wie z. B. eine HTTP-Schnittstelle;
  • das Ereignissystem selbst, das die Übertragung von Ereignissen von Schnittstellen zu Funktionen und die Verarbeitung von Ergebnissen von Funktionen zu Schnittstellen ermöglicht.


Diese drei Komponenten reichen aus, um eine ziemlich komplexe Anwendung zu erstellen. Beispielsweise ist eine Webanwendung nur eine externe HTTP-Schnittstelle (im Fall von AWS ist dies APIGateway ) und für jede verarbeitete Ressource (wie / route / my ) eine eigene Serverless-Handler-Funktion. Sie können eine komplexere Anwendung erstellen, die Datenbanken verwendet und selbst andere Funktionen ohne Server aufruft, wie in der Abbildung dargestellt.



Okay, Sie können solche Anwendungen erstellen, aber warum?



Serverlose Anwendungen bieten mehrere überzeugende Vorteile, die die Architektur in der Hocke rechtfertigen.



  • Serverlose Funktionen funktionieren nicht, wenn sie nicht benötigt werden. In der Tat verarbeitet die Funktion nur Ereignisse - warum sollte sie Rechenressourcen beanspruchen, wenn keine Ereignisse vorhanden sind?
  • Serverlose Funktionen können Ereignisse desselben Typs parallel verarbeiten. Das heißt, wenn / route / my sehr beliebt geworden ist und tausend Benutzer es gleichzeitig angefordert haben, kann die Serverless-Plattform einfach 1000 Handler starten, einen pro Ereignis.


Zusammen ergeben diese Punkte möglicherweise eines der wichtigsten Mantras ohne Server: Die Anwendung ohne Server skaliert von null bis unendlich. Eine solche Anwendung gibt kein Geld aus, wenn sie nicht gefragt ist, und kann bei Bedarf Tausende von Anfragen pro Sekunde verarbeiten.



Problem



Schauen wir uns ein sehr einfaches Beispiel in Kotlin-Sprache an:



@Get("/my/route")
fun handler() = "Hello World"


Es ist ziemlich offensichtlich, dass eine solche Anwendung mit dem Ansatz ohne Server implementiert werden kann. Auf den ersten Blick reicht es aus, eine HTTP-Schnittstelle mit einer DNS-Adresse zu erstellen und / my / route dem fun handler () zuzuordnen .



Tatsächlich würde das Erstellen einer solchen Anwendung viel mehr erfordern als das Hinzufügen einer einzelnen Anmerkung. Zum Beispiel im Fall von AWS:



  • Sie müssen einen Schnittstellenhandler für ein bestimmtes Ereignis implementieren, in diesem Fall den RequestStreamHandler.
  • Sie müssen die Infrastruktur der Serverless-Anwendung beschreiben: Beschreiben Sie die HTTP-API der Anwendung, beschreiben Sie alle Handlerfunktionen und ordnen Sie ihre Funktionen der Schnittstelle zu, indem Sie die Berechtigungen sorgfältig auswählen.
  • Schließlich müssen Sie alle Handlerfunktionen sammeln, in die Serverless-Plattform laden und die entsprechende Infrastruktur bereitstellen.


Es gibt nicht so wenige Schritte für eine so einfache Anwendung, oder?



Für diejenigen, die als Code in das Sakrament der Infrastruktur eingeweiht wurden, werde ich feststellen, dass natürlich ein Teil des Prozesses automatisiert werden kann, aber diese Automatisierung selbst erfordert das Studium eines völlig neuen Ansatzes (in der Tat, die Infrastruktur als Code zu beschreiben) und einer neuen Sprache. Dies scheint eine unnötig schwierige Aufgabe für einen Entwickler zu sein, der eine rudimentäre Anwendung bereitstellen möchte.



Ist es möglich, etwas einfacher zu machen? In einigen Fällen (und speziell in diesem Fall) - ja!



Infrastruktur im Code



Schauen wir uns die andere Seite an: Anstatt den Benutzer zu zwingen, die Infrastruktur zu beschreiben, werden wir versuchen, sie aus dem bereits geschriebenen Benutzercode abzuleiten.



Betrachten Sie das gleiche Beispiel noch einmal:



@Get("/my/route")
fun handler() = "Hello World"


Wir wissen, dass der Benutzer möchte, dass Anfragen an / my / route von dieser Funktion verarbeitet werden. Lassen Sie uns also eine Infrastruktur synthetisieren, die eine HTTP-API mit / my / route erstellt , die erforderliche Funktion ohne Server erstellt und alle erforderlichen Aktionen ausführt, um sie zu verbinden!



In meinem Artikel bei Automated Software Engineering 2019 habe ich diesen Ansatz Infrastruktur im Code genannt. Tatsächlich extrahieren wir die Beschreibung der Infrastruktur aus dem Anwendungscode, der sie implizit definiert, dh sie ist tatsächlich "innerhalb" des Codes enthalten.



Es ist zu beachten, dass im Folgenden nur die Synthese von HTTP-API-Anwendungen betrachtet wird. Ein ähnlicher Ansatz kann für die Verarbeitung von Warteschlangen und für die Verarbeitung von Ereignissen auf der Cloud-Plattform verwendet werden. Dies ist jedoch eine Frage der Weiterentwicklung von Kotless.



Implementierung



Hoffentlich ist an diesem Punkt die Idee klar und es bleiben drei Hauptfragen übrig:



  • Wie extrahiere ich Informationen aus Code?
  • Wie erstelle ich eine Infrastruktur basierend auf diesen Informationen?
  • Wie führe ich eine Anwendung in der Cloud aus?


Analyse



Das Kotlin Compiler Embeddable hilft uns dabei.



Trotz der Tatsache, dass es sich bei dem Beispiel um Anmerkungen handelt, kann die HTTP-API der Anwendung in Abhängigkeit von der verwendeten Bibliothek in der Realität auf völlig unterschiedliche Weise definiert werden, zum Beispiel:



//ktor-like style
get("my-route") {
    "Hello World"
}


Für die Analyse von beliebigem Code erwies sich das Kotlin Compiler Embeddable als vertrauter und praktischer (aufgrund der großen Anzahl von Beispielen).



Derzeit kann Kotless drei Hauptrahmen analysieren:



  • Kotless DSL - Kotless 'eigenes Annotation Framework
  • Spring Boot ist ein beliebtes Webframework. Anmerkungen werden analysiert.
  • Ktor ist ein beliebtes Kotlin Web Framework, Erweiterungsfunktionen werden analysiert.


Bei der Analyse des Codes wird das Kotless-Schema erfasst. Dies ist eine plattformunabhängige Darstellung der Serverless-Anwendung. Es wird zur Synthese der Infrastruktur verwendet und macht den Analyseprozess unabhängig von einer bestimmten Cloud-Plattform.



Synthese



Wir werden Terraform-Code synthetisieren. Terraform wurde als eines der beliebtesten Infrastruktur-Code-Tools mit einer Vielzahl unterstützter Cloud-Plattformen ausgewählt, wodurch sichergestellt wird, dass Kotless neue Cloud-Plattformen und Stabilität bei der Anwendungsbereitstellung unterstützen kann.



Die Synthese erfolgt aus dem Kotless-Schema, das eine Beschreibung der HTTP-API der Anwendung und ihrer Funktionen sowie einige zusätzliche Daten (z. B. den gewünschten DNS-Namen) enthält.



Für die Synthese selbst wird eine speziell erstellte Terraform DSL-Bibliothek verwendet. Der Synthesecode sieht ungefähr so ​​aus:



val resource = api_gateway_rest_api("tf_name") {
    name = "aws_name"
    binary_media_types = arrayOf(MimeType.PNG)
}


DSL garantiert Formatierung und referenzielle Integrität zwischen verschiedenen Terraform-Ressourcen, was die Erweiterung des Satzes synthetisierter Ressourcen erheblich vereinfacht.



Der synthetisierte Code wird mit einer einfachen Terraform-Anwendung auf der Cloud-Plattform bereitgestellt.



Laufen



Die Anwendung muss noch auf der Serverless-Plattform ausgeführt werden. Wie bereits erwähnt, sind alle Funktionen ohne Server im Wesentlichen Handler für einige Ereignisse, in unserem Fall HTTP-Anforderungen.



Es ist erforderlich, das Framework, mit dem die Anwendung erstellt wird (z. B. Spring Boot), und die Serverless-Plattform zu verbinden. Zu diesem Zweck fügt Kotless zum Zeitpunkt der Erstellung der Anwendung dem Anwendungscode einen speziellen "Dispatcher" hinzu - einen plattformspezifischen Ereignishandler, der als Adapter zwischen dem in der Anwendung verwendeten Framework und der Cloud-Plattform dient.



Werkzeug



Das Tool selbst, das die gesamte beschriebene Pipeline zum Erstellen der Infrastruktur enthält, wurde als Plugin für das Gradle-Build-System implementiert. Darüber hinaus sind alle Hauptmodule separate Bibliotheken, was die Unterstützung anderer Build-Systeme erheblich vereinfacht.



Die Verwendung des Plugins ist unkompliziert. Nach der Konfiguration hat der Benutzer nur eine Gradle-Aufgabe - Bereitstellen , die alle erforderlichen Schritte zum Bereitstellen der aktuellen Anwendung in der Cloud ausführt.



Die Anpassung von der Benutzerseite ist auch ziemlich einfach. Das Plugin selbst wird zuerst angewendet:



plugins {
  io("io.kotless") version "0.1.5" apply true
}


Danach fügt der Benutzer das Framework hinzu, das er benötigt:



dependencies {
  //Kotless DSL 
  implementation("io.kotless", "lang", "0.1.5")
}


Schließlich wird der AWS-Zugriff so eingerichtet, dass Kotless Folgendes bereitstellen kann:



kotless {
  config {
    bucket = "kotless.s3.example.com"

    terraform {
      profile = "example"
      region = "us-east-1"
    }
  }
}


Lokaler Start



Es ist leicht zu erkennen, dass der Benutzer für den letzten Punkt mit AWS vertraut sein und mindestens ein AWS-Konto haben muss. Solche Anforderungen schreckten Benutzer ab, die zuerst vor Ort versuchen wollten, ob das Tool für sie geeignet war.



Aus diesem Grund unterstützt Kotless den lokalen Startmodus. Kotless verwendet die Standardfunktionen des ausgewählten Frameworks (Ktor, Spring Boot und Kotless DSL können natürlich Anwendungen lokal ausführen) und stellt die Anwendung auf dem Computer des Benutzers bereit.



Darüber hinaus kann Kotless die AWS-Emulation (von LocalStack verwendet ) ausführen, sodass der Benutzer lokal überprüfen kann, ob sich die Anwendung wie erwartet verhält.



Weitere Entwicklung



Während ich Kotless (und damit meine Masterarbeit) schrieb, gelang es mir, es auf der ASE 2019, der KotlinConf 2019 und im Talking Kotlin-Podcast zu präsentieren. Im Allgemeinen wurde das Tool positiv aufgenommen, obwohl es Ende 2019 nicht mehr so ​​neu zu sein schien (zu diesem Zeitpunkt waren Zappa, Claudia.js und AWS Chalice populär geworden).



Im Moment ist Kotless jedoch wahrscheinlich das berühmteste Werkzeug seiner Klasse in der Kotlin-Welt, und ich plane sicherlich, es weiterzuentwickeln.



In naher Zukunft plane ich, die aktuelle API und Funktionalität zu stabilisieren, Tutorials und Demo-Projekte vorzubereiten, um neuen Benutzern das Erlernen des Tools zu erleichtern.



Zum Beispiel planen wir, eine Reihe von Tutorials zum Erstellen von Chat-Bots mit Kotless vorzubereiten. Es scheint, dass serverlose Technologien für diesen Anwendungsfall großartig sind (und Kotless-Benutzer schreiben bereits Telegramm-Bots), aber das Fehlen geeigneter Tools behindert die weit verbreitete Verwendung erheblich.



Schließlich ist einer der wichtigsten Aspekte der gesamten Architektur des Tools die Plattformunabhängigkeit. Ich hoffe, dass ich in nicht allzu ferner Zukunft die Google Cloud Platform und Microsoft Azure unterstützen kann, mit denen Anwendungen mit nur einer einzigen Schaltfläche von Cloud zu Cloud wechseln können.



Ich würde gerne hoffen, dass Kotless und ähnliche Tools die Einführung von Serverless-Technologien in der Masse wirklich unterstützen und immer mehr Anwendungen nur dann Ressourcen verbrauchen, wenn sie ausgeführt werden, was die Entropie des Universums leicht verringert :)



All Articles