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:MinRAMPercentage
wird 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.
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 | No | 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 | Alle | 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 2000m
cpu_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: