Containerisieren Ihrer Java-Anwendungen

Dieser Artikel enthält eine Übersicht über empfohlene Strategien und Einstellungen für die Containerisierung von Java-Anwendungen.

Berücksichtigen Sie bei der Containerisierung einer Java-Anwendung sorgfältig, wie viel CPU-Zeit der Container verfügbar ist. Überlegen Sie dann, wie viel Arbeitsspeicher sowohl im Hinblick auf die Gesamtspeichermenge als auch die Heap-Größe des virtuellen Java-Computers (JVM) verfügbar ist. In containerisierten Umgebungen haben Anwendungen möglicherweise Zugriff auf alle Prozessoren und können daher mehrere Threads parallel ausführen. Es ist jedoch üblich, dass Container über ein CPU-Kontingent verfügen, das den Zugriff auf CPUs möglicherweise drosselt.

Die JVM verfügt über Heuristiken, um die Anzahl der "verfügbaren Prozessoren" basierend auf dem CPU-Kontingent zu bestimmen, was die Leistung von Java-Anwendungen erheblich beeinflussen kann. Der dem Container zugewiesene Speicher und die Größe des Heapbereichs für das JVM sind ebenso wichtig wie die Prozessoren. Diese Faktoren bestimmen das Verhalten des Garbage Collector (GC) und die Gesamtleistung des Systems.

Containerisieren einer neuen Anwendung

Wenn Sie eine Java-Workload für eine neue Anwendung containern, müssen Sie zwei Dinge berücksichtigen, wenn Sie über Arbeitsspeicher nachdenken:

  • Der dem Container zugeordnete Speicher selbst.
  • Die Für den Java-Prozess verfügbare Arbeitsspeichermenge.

Grundlegendes zu JVM-Standard-Ergonomie

Anwendungen benötigen einen Ausgangspunkt und Einstellungen. Das JVM verfügt über Standard-Ergonomie mit vordefinierten Werten, die auf der Anzahl der verfügbaren Prozessoren und der Menge des Arbeitsspeichers im System basieren. Die in den folgenden Tabellen gezeigten Standardwerte werden verwendet, wenn das JVM ohne bestimmte Startflags oder Parameter gestartet wird.

Die folgende Tabelle zeigt die Standard-GC, die für die verfügbaren Ressourcen verwendet wird:

Verfügbare Ressourcen Standard-GC
Beliebig viele Prozessoren
Bis zu 1791 MB Arbeitsspeicher
SerialGC
2+ Prozessoren
1792 MB oder mehr Arbeitsspeicher
G1GC

Die folgende Tabelle zeigt die standardmäßige maximale Heap-Größe, je nachdem, wie viel Arbeitsspeicher in der Umgebung verfügbar ist, in der der JVM ausgeführt wird:

Verfügbarer Arbeitsspeicher Standardmäßige maximale Heapgröße
Bis zu 256 MB 50 % des verfügbaren Arbeitsspeichers
256 MB bis 512 MB ~127 MB
Mehr als 512 MB 25 % des verfügbaren Arbeitsspeichers

Die standardmäßige anfängliche Heapgröße beträgt 1/64 des verfügbaren Arbeitsspeichers.

Diese Werte gelten für OpenJDK 11 und höher und für die meisten Verteilungen, einschließlich Microsoft Build of OpenJDK, Azul Zulu, Eclipse Temurin, Oracle OpenJDK und anderen.

Bestimmen des Containerspeichers

Wählen Sie einen Containerspeicherbetrag aus, der Ihrer Arbeitslast am besten entspricht, abhängig von den Anforderungen Ihrer Anwendung und den charakteristischen Verwendungsmustern. Wenn Ihre Anwendung beispielsweise große Objektdiagramme erstellt, benötigen Sie wahrscheinlich mehr Arbeitsspeicher als für Anwendungen mit vielen kleinen Objektdiagrammen.

Tipp

Wenn Sie nicht wissen, wie viel Arbeitsspeicher zugewiesen werden soll, ist ein guter Ausgangspunkt 4 GB.

Ermitteln des JVM-Heapspeichers

Beachten Sie beim Zuweisen des JVM-Heapspeichers, dass der JVM mehr Speicher benötigt als nur das, was für den JVM-Heap verwendet wird. Wenn Sie den maximalen JVM-Heapspeicher festlegen, sollte er niemals der Menge des Containerspeichers entsprechen, da dies zu Fehlern im Container außerhalb des Arbeitsspeichers (Out of Memory, OOM) und Containerabstürzen führt.

Tipp

Weisen Sie 75 % des Containerspeichers für den JVM-Heap zu.

Auf OpenJDK 11 und höher können Sie die JVM-Heapgröße auf folgende Weise festlegen:

Beschreibung Flag Beispiele
Fester Wert -Xmx -Xmx4g
Dynamischer Wert -XX:MaxRAMPercentage -XX:MaxRAMPercentage=75

Minimale/anfängliche Heapgröße

Wenn die Umgebung garantiert einen bestimmten Speicherplatz für eine JVM-Instanz reserviert hat, z. B. in einem Container, sollten Sie die minimale Heap-Größe ( oder die anfängliche Heap-Größe ) auf dieselbe Größe wie die maximale Heapgröße festlegen. Diese Einstellung gibt dem JVM an, dass er nicht die Aufgabe ausführen sollte, Arbeitsspeicher auf das Betriebssystem freizugeben.

Verwenden Sie -Xms zum Festlegen einer mindesten Heap-Größe absolute Beträge oder -XX:InitialRAMPercentage prozentuale Beträge.

Wichtig

Das Kennzeichen -XX:MinRAMPercentagewird trotz des Namens verwendet, um den standardmäßigen maximalen RAM-Prozentsatz für Systeme mit bis zu 256 MB RAM festzulegen, der im System verfügbar ist.

Chart showing the default heap size on OpenJDK 17.

Bestimmen der zu verwendenden GC

Zuvor haben Sie die Menge des JVM-Heapspeichers festgelegt, mit dem sie beginnen soll. Der nächste Schritt besteht darin, Ihre GC auszuwählen. Die Menge an maximalem JVM-Heap-Speicher, den Sie haben, ist häufig ein Faktor bei der Auswahl Ihrer GC. In der folgenden Tabelle werden die Merkmale der einzelnen GC-Elemente beschrieben.

Faktoren SerialGC ParallelGC G1GC ZGC ShenandoahGC
Anzahl von Kernen 1 2 2 2 2
Multithreading Nein Ja Ja Ja Ja
Java-Heapgröße <4 GByte <4 GByte >4 GByte >4 GByte >4 GByte
Anhalten Ja Ja Ja Ja (<1 ms) Ja (<10 ms)
Gemeinkosten Mindestens Mindestens Mittel Mittel Mittel
Effekt der Taillatenz High High Hoch Niedrig Moderat
JDK-Version All All JDK 8+ JDK 17+ JDK 11+
Am besten geeignet für Einzelner Kern kleiner Heaps Multikernige kleine Heaps oder Batchworkloads mit jeder Heapgröße Reaktionsfähig in mittelgroßen bis großen Heaps (Anforderungsantwort-/DB-Interaktionen) Reaktionsfähig in mittelgroßen bis großen Heaps (Anforderungsantwort-/DB-Interaktionen) Reaktionsfähig in mittelgroßen bis großen Heaps (Anforderungsantwort-/DB-Interaktionen)

Tipp

Für die meisten allgemeinen Microservice-Anwendungen beginnen Sie mit der Parallel GC.

Ermitteln, wie viele CPU-Kerne benötigt werden

Für jede andere GC als SerialGC empfehlen wir zwei oder mehr vCPU-Kerne – oder mindestens 2000mcpu_limit auf Kubernetes. Es wird nicht empfohlen, etwas weniger als 1 vCPU-Kern in containerisierten Umgebungen auszuwählen.

Tipp

Wenn Sie nicht wissen, mit wie vielen Kernen sie beginnen sollen, ist eine gute Wahl 2 vCPU-Kerne.

Auswählen eines Ausgangspunkts

Es wird empfohlen, mit zwei Replikaten oder Instanzen in Container-Orchestrierungsumgebungen wie Kubernetes, OpenShift, Azure Spring Apps, Azure Container Apps und Azure-App Service zu beginnen. In der folgenden Tabelle sind die empfohlenen Ausgangspunkte für die Containerisierung Ihrer neuen Java-Anwendung zusammengefasst.

vCPU-Kerne Containerspeicher JVM-Heapgröße GC Replikate
2 4 GB 75 % ParallelGC 2

Die zu verwendenden JVM-Parameter lauten wie folgt: -XX:+UseParallelGC -XX:MaxRAMPercentage=75

Containerisieren einer vorhandenen (lokalen) Anwendung

Wenn Ihre Anwendung bereits lokal oder auf einem virtuellen Computer in der Cloud ausgeführt wird, sollten Sie mit folgendem Verfahren beginnen:

  • Die gleiche Arbeitsspeichermenge, auf die die Anwendung derzeit Zugriff hat.
  • Die gleiche Anzahl von CPUs (vCPU-Kernen), die die Anwendung derzeit zur Verfügung hat.
  • Dieselben JVM-Parameter, die Sie derzeit verwenden.

Wenn die vCPU-Kerne und/oder die Containerspeicherkombination nicht verfügbar ist, wählen Sie den nächstgelegenen Kern aus, um die vCPU-Kerne und den Containerspeicher aufzurunden.

Nächste Schritte

Nachdem Sie nun die allgemeinen Empfehlungen für die Containerisierung von Java-Anwendungen verstanden haben, fahren Sie mit dem folgenden Artikel fort, um einen Containerisierungsbasisplan einzurichten: