Website-Suche

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.

Verwandte Artikel: