Avec la sortie de Java 10, qui est une étape importante en termes de chiffres, je pense que la communauté Java profite du printemps après un long moment et est effrayée par la course de mise à jour à venir.
Les nouvelles fonctionnalités de Java 10 ont été introduites dans divers blogs, mais j'ai fait une petite recherche sur le support Docker qui m'intéressait personnellement.
Note de publication Java10: http://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html
A propos de Docker, il y a environ 3 correspondances, mais voici ce qui vous intéresse.
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.
Lorsque la JVM s'exécute dans le conteneur Doocker, elle examinait les paramètres du système d'exploitation sans regarder les paramètres du conteneur Docker, mais Java 10 a amélioré cela. J'ai donc créé à la hâte une image Docker avec Java 10 et l'ai essayée pour voir à quoi elle ressemblait réellement.
L'image Docker a été créée avec ce script. https://gist.github.com/c9katayama/634b14ea65f3910448e0c93b4637a1c1 Vous pouvez créer une image Ubuntu Docker en téléchargeant le script ci-dessus, en définissant le nom d'utilisateur dockerhub de manière appropriée, puis en exécutant la version Oracle JDK Linux tar.gz dans le même dossier.
J'ai également créé des images Java8 (162) et Java9 (9.0.4) à des fins de comparaison. L'environnement d'exécution est Amazon Linux 2017.09 et l'instance EC2 est m4.xlarge (4CPU / mem 16G).
Java8 J'ai exécuté le script suivant.
//démarrer le conteneur Docker
docker run -it c9katayama/java8:162
//implémentation du code java
echo 'public class T{ public static void main(String[] args){ System.out.println("CPU:"+Runtime.getRuntime().availableProcessors()); }}' > T.java
//Compiler et exécuter
javac -cp . T.java && java -cp . T
//résultat
CPU:4
En Java8, lorsque le nombre de processeurs n'était pas spécifié dans le conteneur Docker, 4 ce qui correspond au nombre d'instances pouvait être obtenu. Ensuite, essayez de définir le nombre de processeurs sur 1 lors du démarrage du conteneur Docker (pour être exact, attribuez le deuxième processeur).
//démarrer le conteneur Docker
docker run --cpuset-cpus 1 -it c9katayama/java8:162
//implémentation et exécution de code java (omis)
//résultat
CPU:1
De manière inattendue, j'ai pu obtenir le nombre correct de processeurs alloués au conteneur Docker. Java9 Vient ensuite Java 9. Vous pouvez utiliser JShell à partir de Java9, alors utilisez ceci.
docker run -it c9katayama/java9:9.0.4
jshell
jshell> System.out.println("CPU:"+Runtime.getRuntime().availableProcessors())
CPU:4
Cela a 4 processeurs sans aucun problème. Ensuite, essayez d'allouer le processeur
docker run --cpuset-cpus 1 -it c9katayama/java9:9.0.4
jshell
jshell> System.out.println("CPU:"+Runtime.getRuntime().availableProcessors())
CPU:1
Encore une fois, contrairement aux attentes, j'ai obtenu le nombre correct de processeurs.
Java10 Java 10 est mon préféré, mais comme il l'a été,
docker run -it c9katayama/java10:10
->CPU:4
docker run --cpuset-cpus 1 -it c9katayama/java10:10
->CPU:1
était. Donc, d'après ce que j'ai vérifié, l'option --cpuset-cpus semble fonctionner à partir de Java8, donc
int threadNum = Runtime.getRuntime().availableProcessors() /2;
Un code comme celui-ci ne changera probablement pas son comportement.
Depuis Docker1.13, il semble y avoir une option appelée -cpus, et j'ai également vérifié cela.
Java8
docker run --cpus 1.0 -it c9katayama/java8:162
//réduction
CPU:4
Java9
docker run --cpus 1.0 -it c9katayama/java9:9.0.4
//réduction
CPU:4
Java10
docker run --cpus 1.0 -it c9katayama/java10:10
//réduction
CPU:1
En ce qui concerne l'option --cpus, il semble que Java 9 n'a pas été pris en charge correctement, et dans Java 10, celui attribué au conteneur Docker peut être pris correctement.
Ensuite, vérifions la quantité de mémoire. La méthode à utiliser est
Runtime.getRuntime().maxMemory();
est. Par souci de clarté, nous résumerons avec / sans spécification de quantité de mémoire.
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
Il semble que la valeur par défaut (1/4 de la quantité de mémoire du système d'exploitation) soit définie pour Java8, 9 et 10 en fonction de la quantité de mémoire du système d'exploitation, ce qui est comme prévu (je crains que Java8 soit un peu petit). )
Ensuite, essayez de spécifier la spécification de la mémoire (512 Mo). 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 //Décroît
Java8 et Java9 passent avec brio les paramètres du conteneur Docker, mais Java10 semble définir la quantité de mémoire maximale en fonction des spécifications du conteneur Docker.
D'après ce que j'ai vérifié, il ne semble y avoir aucun problème avec le processeur (du moins pour l'option --cpuset-cpus), mais l'option --cpus semble être mieux examinée car elle se comporte différemment. Surtout lors de l'utilisation de paralellStream (), le nombre de threads utilisés dépend du nombre de processeurs, ce qui peut affecter les performances.
En ce qui concerne la mémoire, il peut y avoir un problème dans le cas où 1. la quantité de mémoire a été spécifiée dans le conteneur Docker 2. JavaVM n'a pas d'option de mémoire et semble avoir bien fonctionné jusqu'à présent.
J'ai demandé à @sugarlife (https://twitter.com/sugarlife) de me dire qu'il existe une option JVM (-XX: -UseContainerSupport) qui élimine ce comportement. https://twitter.com/sugarlife/status/976355508343881729
Lorsque je l'ai effectivement transmis à la JVM, il est revenu au comportement avant Java 9.
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 //Exécuter avec des options
MEM:4014M
Dans tous les cas, je pense qu'il est normal de revoir la zone mémoire une fois dans Java 10.
Allocation des ressources Docker: https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler
Recommended Posts