Mit der Veröffentlichung von Java 10, einem Meilenstein in Bezug auf die Anzahl, denke ich, dass die Java-Community nach langer Zeit den Frühling genießt und Angst vor dem bevorstehenden Update-Rennen hat.
Die neuen Funktionen von Java 10 wurden in verschiedenen Blogs vorgestellt, aber ich habe ein wenig über die Docker-Unterstützung recherchiert, an der ich persönlich interessiert war.
Java10-Versionshinweis: http://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html
Über Docker gibt es ungefähr 3 Korrespondenzen, aber hier ist, woran Sie interessiert sind.
Improve docker container detection and resource configuration usage
The following changes have been introduced in JDK 10 to improve the execution and configurability of Java running in Docker containers:
JDK-8146115 Improve docker container detection and resource configuration usage
The JVM has been modified to be aware that it is running in a Docker container and will extract container specific configuration information instead of querying the operating system. The information being extracted is the number of CPUs and total memory that have been allocated to the container. The total number of CPUs available to the Java process is calculated from any specified cpu sets, cpu shares or cpu quotas. This support is only available on Linux-based platforms. This new support is enabled by default and can be disabled in the command line with the JVM option:
-XX:-UseContainerSupport
In addition, this change adds a JVM option that provides the ability to specify the number of CPUs that the JVM will use:
-XX:ActiveProcessorCount=count
This count overrides any other automatic CPU detection logic in the JVM.
Wenn die JVM im Doocker-Container ausgeführt wird, wurden früher die Betriebssystemeinstellungen und nicht die Docker-Containereinstellungen überprüft. Java 10 hat dies jedoch verbessert. Also habe ich schnell ein Docker-Image mit Java 10 erstellt und versucht, zu sehen, wie es tatsächlich aussieht.
Das Docker-Image wurde mit diesem Skript erstellt. https://gist.github.com/c9katayama/634b14ea65f3910448e0c93b4637a1c1 Nachdem Sie das obige Skript heruntergeladen und den Benutzernamen von Dockerhub entsprechend festgelegt haben, können Sie ein Docker-Image von Ubuntu erstellen, indem Sie tar.gz für Linux von Oracle JDK im selben Ordner ausführen.
Zum Vergleich habe ich auch Java 8 (162) - und Java 9 (9.0.4) -Bilder erstellt. Die Ausführungsumgebung ist Amazon Linux 2017.09 und die EC2-Instanz ist m4.xlarge (4CPU / mem 16G).
Java8 Ich habe das folgende Skript ausgeführt.
//Docker-Container starten
docker run -it c9katayama/java8:162
//Java-Code-Implementierung
echo 'public class T{ public static void main(String[] args){ System.out.println("CPU:"+Runtime.getRuntime().availableProcessors()); }}' > T.java
//Kompilieren und ausführen
javac -cp . T.java && java -cp . T
//Ergebnis
CPU:4
Wenn in Java8 die Anzahl der Prozessoren nicht im Docker-Container angegeben wurde, 4 konnte die Anzahl der Instanzen ermittelt werden. Versuchen Sie als Nächstes, die Anzahl der CPUs beim Starten des Docker-Containers auf 1 zu setzen (um genau zu sein, weisen Sie den zweiten Prozessor zu).
//Docker-Container starten
docker run --cpuset-cpus 1 -it c9katayama/java8:162
//Implementierung und Ausführung von Java-Code (weggelassen)
//Ergebnis
CPU:1
Unerwartet konnte ich die richtige Anzahl von CPUs erhalten, die dem Docker-Container zugewiesen waren. Java9 Als nächstes kommt Java 9. Sie können JShell von Java9 aus verwenden, verwenden Sie dies also.
docker run -it c9katayama/java9:9.0.4
jshell
jshell> System.out.println("CPU:"+Runtime.getRuntime().availableProcessors())
CPU:4
Dies hat 4 CPUs ohne Probleme. Versuchen Sie als Nächstes, die CPU zuzuweisen
docker run --cpuset-cpus 1 -it c9katayama/java9:9.0.4
jshell
jshell> System.out.println("CPU:"+Runtime.getRuntime().availableProcessors())
CPU:1
Entgegen den Erwartungen habe ich wieder die richtige Anzahl von CPUs bekommen.
Java10 Java 10 ist mein Favorit, aber wie es war,
docker run -it c9katayama/java10:10
->CPU:4
docker run --cpuset-cpus 1 -it c9katayama/java10:10
->CPU:1
war. Soweit ich überprüft habe, scheint die Option --cpuset-cpus von Java8 aus zu funktionieren
int threadNum = Runtime.getRuntime().availableProcessors() /2;
Es ist unwahrscheinlich, dass ein solcher Code sein Verhalten ändert.
Ab Docker1.13 scheint es eine Option namens -cpus zu geben, und ich habe dies auch überprüft.
Java8
docker run --cpus 1.0 -it c9katayama/java8:162
//Kürzung
CPU:4
Java9
docker run --cpus 1.0 -it c9katayama/java9:9.0.4
//Kürzung
CPU:4
Java10
docker run --cpus 1.0 -it c9katayama/java10:10
//Kürzung
CPU:1
In Bezug auf die Option --cpus scheint Java 9 nicht korrekt unterstützt worden zu sein, und in Java 10 kann die dem Docker-Container zugewiesene Option korrekt übernommen werden.
Als nächstes überprüfen wir die Speichermenge. Die zu verwendende Methode ist
Runtime.getRuntime().maxMemory();
ist. Aus Gründen der Klarheit werden wir mit / ohne Speichermengenangabe zusammenfassen.
Java8
docker run -it c9katayama/java8:162
echo 'public class T{ public static void main(String[] args){ System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M"); }}' > T.java
javac -cp . T.java && java -cp . T
MEM:3568M
Java9
docker run -it c9katayama/java9:9.0.4
jshell> System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M")
MEM:4014M
Java10
docker run -it c9katayama/java10:10
jshell> System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M")
MEM:4014M
Es scheint, dass der Standardwert (1/4 der Betriebssystemspeichermenge) für Java8, 9 und 10 basierend auf der Betriebssystemspeichermenge festgelegt wird, was wie erwartet ist (ich mache mir Sorgen, dass Java8 etwas klein ist). )
Versuchen Sie als Nächstes, die Speicherspezifikation (512 MB) anzugeben. Java8
docker run -m 512m -it c9katayama/java8:162
echo 'public class T{ public static void main(String[] args){ System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M"); }}' > T.java
javac -cp . T.java && java -cp . T
MEM:3568M
Java9
docker run -m 512m -it c9katayama/java9:9.0.4
jshell> System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M")
MEM:4014M
Java10
docker run -m 512m -it c9katayama/java10:10
jshell> System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M")
MEM:123M //Nimmt ab
Java8 und Java9 durchlaufen die Docker-Containereinstellungen auf brillante Weise, aber Java10 scheint die maximale Speichermenge basierend auf den Docker-Containerspezifikationen festzulegen.
Soweit ich überprüft habe, scheint es kein Problem mit der CPU zu geben (zumindest für die Option --cpuset-cpus), aber die Option --cpus scheint besser überprüft zu werden, da sie sich anders verhält. Insbesondere bei Verwendung von paralellStream () hängt die Anzahl der verwendeten Threads von der Anzahl der Prozessoren ab, was die Leistung beeinträchtigen kann.
In Bezug auf den Speicher kann ein Problem auftreten, wenn 1. die Speichermenge im Docker-Container angegeben wurde 2. JavaVM keine Speicheroption hat und bisher anscheinend gut funktioniert hat.
Ich habe @sugarlife (https://twitter.com/sugarlife) gebeten, mir mitzuteilen, dass es eine JVM-Option (-XX: -UseContainerSupport) gibt, die dieses Verhalten beseitigt. https://twitter.com/sugarlife/status/976355508343881729
Als ich es tatsächlich an die JVM übergeben habe, kehrte es zum Verhalten vor Java 9 zurück.
docker run -m 512m -it c9katayama/java10:10
echo 'public class T{ public static void main(String[] args){ System.out.println("MEM:"+Runtime.getRuntime().maxMemory()/1024/1024+"M"); }}' > T.java
javac -cp . T.java
java -XX:-UseContainerSupport -cp . T //Mit Optionen ausführen
MEM:4014M
In jedem Fall denke ich, dass es in Ordnung ist, den Speicherbereich einmal in Java 10 zu überprüfen.
Docker-Ressourcenzuweisung: https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
Recommended Posts