Post-scriptum du 08/04/2018: Ajout d'une description de Java 10 au résumé.
Post-scriptum du 02/06/2017: Le contenu de l'enquête a été résumé et la description a été considérablement mise à jour.
Addendum du 01/06/2017: Ajout de "Efforts pour ce problème après JDK 8/9" à la fin de l'article. Il semble que cela ait été corrigé dans 8u121.b34 et 8u131.b06 d'OpenJDK8 (je vérifierai séparément si c'est vraiment corrigé). Les deux solutions de contournement ont été publiées depuis 2017, c'est donc une bonne idée de vérifier si vous ne mettez pas à jour votre JDK / JRE fréquemment.
Java10 prend désormais officiellement en charge les conteneurs Docker. Le programme Java sur le conteneur Docker peut désormais saisir les paramètres de ressources tels que le processeur et la mémoire définis dans le conteneur Docker, de sorte que le problème Menikoa décrit dans cet article sera résolu.
Concernant la prise en charge de Java 10 et Docker, l'article Qiita suivant résume en détail, y compris la vérification des opérations.
https://qiita.com/c9katayama/items/b427a008623f0e228c50
Si vous limitez le nombre de processeurs à un petit nombre avec Docker, ensemble de tâches, etc. dans l'environnement Menicoa, les performances des programmes Java peuvent chuter considérablement. Il y a deux manières de le gérer.
Si vous n'utilisez que l'option pour spécifier l'ID du cœur du processeur, comme le --cpuset-cpus de la commande --docker, vous pouvez le gérer avec une mise à jour JDK. (Java 8 8u121.b34 ou version ultérieure ou 8u131.b06 ou version ultérieure) --Si vous utilisez une option qui ne spécifie pas d'ID de cœur de processeur, telle que la commande docker --cpus, vous devez régler les paramètres de paramètres JVM appropriés lorsque vous démarrez le programme Java.
Dans un environnement menicoa (une machine avec un grand nombre de cœurs de processeur), les performances chuteront considérablement lorsqu'un programme Java est exécuté sur un Docker qui a des restrictions de ressources telles que le nombre de cœurs de processeur. Il en va de même lorsqu'un programme Java est exécuté à l'aide d'une technologie ou d'une commande de conteneur (par exemple, la commande Tasket) qui utilise des restrictions de ressources par des groupes de contrôle autres que Docker.
En Java, les paramètres JVM suivants sont définis en fonction des ressources matérielles de la machine.
--Nombre de threads GC (garbage collection) --Nombre de threads de compilation JIT
C'est bien en soi. Cependant, en Java, même si les ressources matérielles sont limitées par un groupe de contrôle tel que Docker, les paramètres JVM sont déterminés en fonction des ressources matérielles de la machine hôte et non des ressources matérielles limitées.
Par conséquent, par exemple, si un programme Java est exécuté sur un «conteneur Docker avec 20 cœurs de processeur» sur une machine hôte avec 20 cœurs de processeur, Java déterminera les paramètres JVM en fonction des 20 cœurs. .. Cependant, le fait qu'un seul cœur de processeur puisse être utilisé dans le conteneur Docker reste le même, de sorte que les programmes Java souffrent de la surcharge d'un grand nombre de threads GC et de threads de compilation JIT en plus du traitement de l'application, ce qui entraîne une diminution significative des performances. ..
Faites attention à ceux qui remplissent les conditions suivantes.
Il existe deux approches principales pour y faire face.
Comme décrit dans «(Référence) Résolution de ce problème après JDK8 / 9» de cet article, les problèmes liés aux groupes de contrôle ont été résolus dans une certaine mesure dans la nouvelle version de JDK8 / 9. Dans le cas de JDK8, il sera résolu en mettant à jour vers la version suivante ou ultérieure.
--8u121.b34 ou version ultérieure --8u131.b06 ou version ultérieure
Les résultats de la confirmation dans le conteneur Docker avec le JDK avant et après l'action sont répertoriés ci-dessous. Je l'ai confirmé dans un environnement avec 8 cœurs de processeur logiques, mais dans le JDK après y avoir traité, la limite de ressources est correctement reflétée dans le paramètre JVM par la commande docker --cpuset-cpus.
#--------------------------------------------------------------
#Dans le JDK pré-action--cpuset-Le réglage de l'option cpus n'est pas reflété dans le paramètre JVM
#--------------------------------------------------------------
$ docker run --rm --cpuset-cpus 0-1 openjdk:8u77-b03 java -XX:+PrintFlagsFinal -version | egrep "CICompilerCount |ParallelGCThreads"
intx CICompilerCount := 4 {product}
uintx ParallelGCThreads = 8 {product}
openjdk version "1.8.0_03-Ubuntu"
OpenJDK Runtime Environment (build 1.8.0_03-Ubuntu-8u77-b03-3ubuntu3-b03)
OpenJDK 64-Bit Server VM (build 25.03-b03, mixed mode)
#--------------------------------------------------------------
#Après avoir traité avec JDK--cpuset-Le réglage de l'option cpus est reflété dans le paramètre JVM
#--------------------------------------------------------------
$ docker run --rm --cpuset-cpus 0-1 openjdk:8u131-b11 java -XX:+PrintFlagsFinal -version | egrep "CICompilerCount |ParallelGCThreads"
intx CICompilerCount := 2 {product}
uintx ParallelGCThreads = 2 {product}
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-0ubuntu1.16.04.2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Cependant, dans le cas d'une option qui ne spécifie pas un ID de cœur de processeur spécifique tel que --cpus de la commande docker, il semble que le problème ne puisse pas être évité même avec Java après manipulation. Je ne l'ai pas essayé, mais il semble probable que ce problème ne puisse pas être évité pour les options --cpu-quota et --cpu-period également. Dans ce cas, il est nécessaire de régler les paramètres des paramètres JVM, ce qui constitue une autre solution de contournement.
#--------------------------------------------------------------
#Après y avoir traité, même en JDK--Aucun effet avec les paramètres des options de processeur
#--------------------------------------------------------------
docker run --rm --cpus 2.0 openjdk:8u131-b11 java -XX:+PrintFlagsFinal -version | egrep "CICompilerCount |ParallelGCThreads"
intx CICompilerCount := 4 {product}
uintx ParallelGCThreads = 8 {product}
openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-0ubuntu1.16.04.2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Il peut être résolu en réglant en définissant le paramètre JVM lors de l'exécution du programme Java sur le conteneur Docker. Cela prend plus de temps qu'une mise à jour JDK, mais c'est la plus fiable.
Vous souhaiterez peut-être définir le GC sur un GC série si les conditions suivantes sont remplies:
#Changer GC en GC série
java -XX:+UseSerialGC ...
Cependant, il est dit que Serial GC sera aboli dans le futur, donc soyez prudent si vous prévoyez de mettre à jour Java.
Si vous souhaitez utiliser Parallel GC, qui est le GC par défaut de Java8, vous pouvez le gérer en réduisant le nombre de threads de Parallel GC. Le nombre approprié de threads dépend de la limite de ressources CPU spécifiée dans la commande docker, un réglage est donc nécessaire.
#Définissez le nombre de threads parallelGC sur 1
java XX:ParallelGCThreads=1 ...
Je n'ai pas défini CSM, G1, etc., donc je ne vais pas le décrire, mais en gros, vous pouvez définir le nombre de threads en fonction des ressources du processeur.
La compilation JIT s'exécute également sur plusieurs threads, et un nombre raisonnable de threads sera généré dans l'environnement Menikoa. Par conséquent, cela doit également être réglé en fonction de la limite de ressources du processeur.
#Définissez le nombre de threads de compilation JIT sur 1
java -XX:CICompilerCount=1 ...
Les paramètres JVM sont déterminés en fonction du programme Java sur la machine virtuelle et des ressources matérielles de la machine virtuelle. Par conséquent, même si la machine hôte se trouve dans un environnement menicoa, les paramètres JVM sont définis en fonction des ressources matérielles affectées à la machine virtuelle.
Ce problème a été reconnu depuis JDK9, et il semble que le problème soit rétroporté vers JDK8 en ce qui concerne l'état de prise en charge du problème. Et il a été traité dans JDK8 "8u121.b34" et "8u131.b06".
Recommended Posts