Optimieren Sie serverlose Java-Funktionen in Kubernetes
Erzielen Sie einen schnelleren Start und einen geringeren Speicherbedarf, um serverlose Funktionen auf Kubernetes auszuführen.
Ein schnellerer Start und ein geringerer Speicherbedarf sind in Kubernetes immer wichtig, da die Ausführung Tausender Anwendungs-Pods kostspielig ist und die Kosteneinsparungen durch weniger Worker-Knoten und andere Ressourcen entstehen. Der Arbeitsspeicher ist bei containerisierten Mikrodiensten auf Kubernetes wichtiger als der Durchsatz, weil:
- Aufgrund der Permanenz ist es teurer (im Gegensatz zu CPU-Zyklen).
- Microservices vervielfachen die Gemeinkosten
- Aus einer monolithischen Anwendung werden N Microservices (z. B. 20 Microservices ≈ 20 GB)
Dies wirkt sich erheblich auf die serverlose Funktionsentwicklung und das Java-Bereitstellungsmodell aus. Dies liegt daran, dass viele Unternehmensentwickler Alternativen wie Go, Python und Nodejs gewählt haben, um den Leistungsengpass zu überwinden – bisher dank Quarkus, einem neuen Kubernetes-nativen Java-Stack. In diesem Artikel wird erläutert, wie Sie die Java-Leistung optimieren, um mithilfe von Quarkus serverlose Funktionen auf Kubernetes auszuführen.
Container-First-Design
Herkömmliche Frameworks im Java-Ökosystem haben ihren Preis in Bezug auf den Speicher und die Startzeit, die zum Initialisieren dieser Frameworks erforderlich sind, einschließlich Konfigurationsverarbeitung, Klassenpfad-Scanning, Laden von Klassen, Annotationsverarbeitung und Erstellung eines Metamodells der Welt, was das Framework erfordert arbeiten. Dies wird für verschiedene Frameworks immer wieder multipliziert.
Quarkus hilft bei der Behebung dieser Java-Leistungsprobleme, indem es fast den gesamten Overhead auf die Build-Phase „nach links verlagert“. Indem Sie die Code- und Framework-Analyse, die Bytecode-Transformation und die dynamische Metamodellgenerierung nur einmal, nämlich zur Erstellungszeit, durchführen, erhalten Sie am Ende eine hochoptimierte ausführbare Laufzeitdatei, die superschnell startet und aufgrund der Arbeit nicht den gesamten Speicher eines herkömmlichen Startvorgangs benötigt wird einmalig in der Build-Phase durchgeführt.
(Daniel Oh, CC BY-SA 4.0)
Noch wichtiger ist, dass Sie mit Quarkus eine native ausführbare Datei erstellen können, die Leistungsvorteile bietet, darunter eine erstaunlich schnelle Startzeit und einen unglaublich kleinen RSS-Speicher (Resident Set Size), für eine sofortige Skalierung und eine Speicherauslastung mit hoher Dichte im Vergleich zur herkömmlichen Cloud. nativer Java-Stack.
(Daniel Oh, CC BY-SA 4.0)
Hier ist ein kurzes Beispiel dafür, wie Sie mit Quarkus die native ausführbare Datei mit einem serverlosen Java-Funktionsprojekt erstellen können.
1. Erstellen Sie das serverlose Maven-Projekt Quarkus
Dieser Befehl generiert ein Quarkus-Projekt (z. B. quarkus-serverless-native
), um eine einfache Funktion zu erstellen:
$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=quarkus-serverless-native \
-DclassName="org.acme.getting.started.GreetingResource"
2. Erstellen Sie eine native ausführbare Datei
Sie benötigen eine GraalVM, um eine native ausführbare Datei für die Java-Anwendung zu erstellen. Sie können eine beliebige GraalVM-Distribution wählen, beispielsweise Oracle GraalVM Community Edition (CE) und Mandrel (die Downstream-Distribution von Oracle GraalVM CE). Mandrel wurde entwickelt, um die Erstellung von Quarkus-nativen ausführbaren Dateien auf OpenJDK 11 zu unterstützen.
Öffnen Sie pom.xml
und Sie finden dieses native
Profil. Sie verwenden es, um eine native ausführbare Datei zu erstellen:
<profiles>
<profile>
<id>native</id>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
Hinweis: Sie können die GraalVM- oder Mandrel-Distribution lokal installieren. Sie können auch das Mandrel-Container-Image herunterladen, um es zu erstellen (wie ich es getan habe), Sie müssen also eine Container-Engine (z. B. Docker) lokal ausführen.
Vorausgesetzt, Sie haben Ihre Containerlaufzeit bereits gestartet, führen Sie einen der folgenden Maven-Befehle aus.
Für Docker:
$ ./mvnw package -Pnative \
-Dquarkus.native.container-build=true \
-Dquarkus.native.container-runtime=docker
Für Podman:
$ ./mvnw package -Pnative \
-Dquarkus.native.container-build=true \
-Dquarkus.native.container-runtime=podman
Die Ausgabe sollte mit BUILD SUCCESS
enden.
(Daniel Oh, CC BY-SA 4.0)
Führen Sie die native ausführbare Datei direkt ohne Java Virtual Machine (JVM) aus:
$ target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner
Die Ausgabe sieht folgendermaßen aus:
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO [io.quarkus] (main) quarkus-serverless-native 1.0.0-SNAPSHOT native
(powered by Quarkus xx.xx.xx.) Started in 0.019s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile prod activated.
INFO [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy]
Überschall! Das sind 19 Millisekunden bis zum Start. Die Zeit kann in Ihrer Umgebung anders sein.
Außerdem weist es eine extrem geringe Speichernutzung auf, wie das Linux-Dienstprogramm ps
meldet. Führen Sie diesen Befehl in einem anderen Terminal aus, während die App ausgeführt wird:
$ ps -o pid,rss,command -p $(pgrep -f runner)
Sie sollten etwa Folgendes sehen:
PID RSS COMMAND
10246 11360 target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner
Dieser Vorgang beansprucht etwa 11 MB Speicher (RSS). Ziemlich kompakt!
Hinweis: Der RSS- und Speicherverbrauch jeder App, einschließlich Quarkus, variiert je nach Ihrer spezifischen Umgebung und steigt mit der Auslastung der Anwendungserfahrungen.
Sie können die Funktion auch mit einer REST-API aufrufen. Dann sollte die Ausgabe Hello RESTEasy
lauten:
$ curl localhost:8080/hello
Hello RESTEasy
3. Stellen Sie die Funktionen für den Knative-Dienst bereit
Wenn Sie dies noch nicht getan haben, erstellen Sie einen Namespace (z. B. quarkus-serverless-native
) auf OKD (OpenShift Kubernetes Distribution), um diese native ausführbare Datei als serverlose Funktion bereitzustellen. Fügen Sie dann eine quarkus-openshift
-Erweiterung für die Knative-Dienstbereitstellung hinzu:
$ ./mvnw -q quarkus:add-extension -Dextensions="openshift"
Hängen Sie die folgenden Variablen in src/main/resources/application.properties
an, um Knative- und Kubernetes-Ressourcen zu konfigurieren:
quarkus.container-image.group=quarkus-serverless-native
quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
quarkus.native.container-build=true
quarkus.kubernetes-client.trust-certs=true
quarkus.kubernetes.deployment-target=knative
quarkus.kubernetes.deploy=true
quarkus.openshift.build-strategy=docker
Erstellen Sie die native ausführbare Datei und stellen Sie sie dann direkt im OKD-Cluster bereit:
$ ./mvnw clean package -Pnative
Hinweis: Stellen Sie sicher, dass Sie sich vorab mit dem Befehl
oc login
beim richtigen Projekt anmelden (z. B.quarkus-serverless-native
).
Die Ausgabe sollte mit BUILD SUCCESS
enden. Es wird einige Minuten dauern, einen nativen Binär-Build abzuschließen und einen neuen Knative-Dienst bereitzustellen. Nach erfolgreicher Erstellung des Dienstes sollten Sie einen Knative-Dienst (KSVC) und eine Revision (REV) sehen, indem Sie entweder das Befehlstool kubectl
oder oc
verwenden:
$ kubectl get ksvc
NAME URL [...]
quarkus-serverless-native http://quarkus-serverless-native-[...].SUBDOMAIN True
$ kubectl get rev
NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON
quarkus-serverless-native-00001 quarkus-serverless-native quarkus-serverless-native-00001 1 True
4. Greifen Sie auf die native ausführbare Funktion zu
Rufen Sie den Endpunkt der serverlosen Funktion ab, indem Sie diesen kubectl
-Befehl ausführen:
$ kubectl get rt/quarkus-serverless-native
Die Ausgabe sollte wie folgt aussehen:
NAME URL READY REASON
quarkus-serverless-native http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN True
Greifen Sie mit einem curl
-Befehl auf die Route URL
zu:
$ curl http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN/hello
In weniger als einer Sekunde erhalten Sie das gleiche Ergebnis wie vor Ort:
Hello RESTEasy
Wenn Sie auf die Protokolle des Quarkus-Ausführungspods im OKD-Cluster zugreifen, sehen Sie, dass die native ausführbare Datei als Knative-Dienst ausgeführt wird.
(Daniel Oh, CC BY-SA 4.0)
Was kommt als nächstes?
Sie können serverlose Java-Funktionen mit GraalVM-Distributionen optimieren, um sie als serverlose Funktionen auf Knative mit Kubernetes bereitzustellen. Quarkus ermöglicht diese Leistungsoptimierung durch einfache Konfigurationen in normalen Microservices.
Der nächste Artikel dieser Reihe führt Sie durch die Erstellung portabler Funktionen auf mehreren serverlosen Plattformen ohne Codeänderungen.