Red Hat 㧠Java Platform Advocate ã¨ã㦠OpenJDK ãæ å½ãã¦ããä¼è¤ã¡ã²ãï¼@chiroitoï¼ã§ãã
ãã®è¨äºã¯ãRed Hat Developerã®ããã°è¨äºãBest practices for Java in single-core containers | Red Hat Developer ã®ç¿»è¨³è¨äºã§ãã
ã³ã³ããã§åä½ããJavaã¢ããªã±ã¼ã·ã§ã³ã®æ°ãå¢ãã¦ãã¾ããã³ã³ããã®æ¡ç¨ã¯ãç¹å®ã®ãã¼ã ãä¼æ¥ã®å¸å ´åºåã ã¯ã©ã¦ãã®æç度ã«ããã®ã§ãæ£ç¢ºãªæ°ã決å®ããã®ã¯å°é£ã§ãããã¨ãã°ãNew Relic ã®ãã¼ã¿ã§ã¯ã顧客㮠Java ã¯ã¼ã¯ãã¼ãã® 62% 以ä¸ãã³ã³ããã§å®è¡ããã¦ãã¾ããä»ã®ãã¼ã¿ã¨åæ§ããã®ãã¼ã¿ãå¸å ´å ¨ä½ã«å¯¾ãã代ç¨ã¨ãã¦ä¸å®å ¨ãªãã®ã§ãããããããã®ã¬ãã¼ãã¯ãJavaå¸å ´ã®éè¦ãªä¸é¨åããã§ã«ã³ã³ãããã¼ã¹ã®ç°å¢ã«ç§»è¡ãã¦ãããã¨ã証æãã¦ãã¾ããã¾ãããããã移è¡ã®æµããã¾ã çµãã£ã¦ããªããã¨ãããã¾ãã¾ãªãã¼ã¿ããããããç¥ãã¾ãã
Javaã使ç¨ãã¦ãããã¼ã ã¯ãã³ã³ãããã¼ã¹ã®å°å ¥ã«ãããããã¤ãã®å´é¢ã«ç¹å¥ãªæ³¨æãæããããã¤ãã®ãã¹ããã©ã¯ãã£ã¹ãæ¡ç¨ããå¿ è¦ãããã¾ãããã®è¨äºã§ã¯ãã¬ãã¼ã¸ã³ã¬ã¯ã¿ï¼GCï¼ã®é¸æã¨ãå©ç¨å¯è½ãª CPUæ°ã¨ã¡ã¢ãªã«åºã¥ãããã©ã«ãã®é¸ææ¹æ³ã«ç¦ç¹ãå½ã¦ã¾ãã
Javaã¢ããªã±ã¼ã·ã§ã³ã®ã©ã¤ããµã¤ã¯ã«
å¾æ¥ã®Javaã¢ããªã±ã¼ã·ã§ã³ã®ã©ã¤ããµã¤ã¯ã«ã¯ãããã¤ãã®ãã§ã¼ãºã§æ§æããã¦ãã¾ããèµ·åã大éã®ã¯ã©ã¹èªã¿è¾¼ã¿ãã¸ã£ã¹ãã¤ã³ã¿ã¤ã ï¼JITï¼ã³ã³ãã¤ã«ã«ããã¦ã©ã¼ã ã¢ãããããã¦ãã¯ã©ã¹èªã¿è¾¼ã¿ãJITãæ¯è¼çå°ãªãæ°æ¥ããæ°é±éç¶ãé·ãæç¶çç¶æ ãç¶ãã¾ããããã¯ãJavaããµã¼ãã¼ãµã¤ãã®æè¡ã¨ãã¦ã¹ã¿ã¼ãããJVMããã¼ã¿ã»ã³ã¿ã¼ã®ãªã³ãã¬ä¸ã§åä½ãã¦ããæ代ãæãåºãã°ãç´å¾ãããã¾ãã
ãã®ä¸çã§ã¯ãã¯ã©ã¹ã¿ã®æ¡å¼µã«ã¯ç©çãã·ã³ã追å 注æãã¦ãã¼ã¿ã»ã³ã¿ã¼ã«é éãã¦ãããå¿ è¦ããããã¢ããªã±ã¼ã·ã§ã³ã®ãã¼ã¸ã§ã³ã¢ããã¯ããããæ°ã«æãã¨ã«è¡ãããã¢ããªã±ã¼ã·ã§ã³ããã»ã¹ã¯é±ã¾ãã¯æåä½ã§ç¨¼åæéã測å®ãã¦ãã¾ãããJavaã¢ããªã±ã¼ã·ã§ã³ã®æ¡å¼µæ§ã¯ãé常ãã¹ã±ã¼ã«ã¢ããã«ç¦ç¹ãå½ã¦ããã¦ããã大éã®ã¡ã¢ãªãæè¼ãã大è¦æ¨¡ãªãã«ãã³ã¢ãã·ã³ä¸ã§Javaãå¹ççã«åä½ããããã¨ãç®æ¨ã§ããã
ãã®ãããªJavaã¢ããªã±ã¼ã·ã§ã³ã®å°å ¥ã¢ãã«ã¯ãããã¤ãã®ç°ãªããé¢é£ããæ¹æ³ããã¯ã©ã¦ãå°å ¥ã®èª²é¡ã¨ãªã£ã¦ãã¾ãã
- ã³ã³ããã®å¯¿å½ã¯ãã£ã¨çããããããªãï¼å ´åã«ãã£ã¦ã¯æ°ç§ï¼ã
- ã¯ã©ã¹ã¿ãµã¤ãºã¯åçã«å調æ´ã¾ãã¯åæ§æãããããããã¾ããï¼ä¾ï¼Kubernetesï¼ã
- ãã¤ã¯ããµã¼ãã¹ã¢ã¼ããã¯ãã£ã¯ãããã»ã¹ãµã¤ãºãå°ãããªãã寿å½ãçããªãå¾åãããã¾ãã
ãããã®ãã¨ãããå¤ãã®éçºè ã¯ãJavaã¢ããªã±ã¼ã·ã§ã³ãã³ã³ããã«ç§»è¡ããéãã§ããã ãå°ããªã³ã³ããã使ç¨ãããã¨ãã¾ããã¯ã©ã¦ããã¼ã¹ã®ã¢ããªã±ã¼ã·ã§ã³ã¯é常ã使ç¨ããRAMã¨CPUã®éã«ãã£ã¦èª²éããããããããã¯çã«ããªã£ã¦ãã¾ãã
ããããããã«ã¯ãJavaã®å°é家ã§ã¯ãªãã¨ã³ã¸ãã¢ã«ã¯ããããªãå¾®å¦ãªãã¥ã¢ã³ã¹ãããã¾ãã詳ããè¦ã¦ããã¾ãããã
åçãªå®è¡ãã©ãããã©ã¼ã ã¨ãã¦ã®JVM
JVMã¯ããããå®è¡ããã¦ãããã·ã³ã®å®æ ã«åããã¦ãèµ·åæã«ç¹å®ã®éè¦ãªãã©ã¡ã¼ã¿ãè¨å®ãããé常ã«åçãªãã©ãããã©ã¼ã ã§ãããããã®ããããã£ã«ã¯ãJVMãèªèããCPUã®æ°ã¨ç¨®é¡ãå©ç¨å¯è½ãªç©çã¡ã¢ãªãå«ã¾ãã¾ããå®è¡ä¸ã®ã¢ããªã±ã¼ã·ã§ã³ã®åä½ã¯ãç°ãªããµã¤ãºã®ãã·ã³ã§å®è¡ãããå ´åã«ã¯ãç°ãªããã®ã«ãªãå¯è½æ§ãããã¾ãããããã¯ã³ã³ããã«ãå½ã¦ã¯ã¾ãã¾ãã
JVMãèµ·åæã«ç¢ºèªããåçãªããããã£ã«ã¯ã次ã®ãããªãã®ãããã¾ãã
- JVMçµã¿è¾¼ã¿é¢æ°ï¼ç¹å®ã®CPUæ©è½ï¼ãã¯ãã«ãµãã¼ããSIMDãªã©ï¼ã«ä¾åãããããã©ã¼ãã³ã¹ãéè¦ãªã¡ã½ããã®ç¬èªã«ãã¥ã¼ãã³ã°ãããå®è£
- å é¨ã¹ã¬ãããã¼ã«ï¼å ±éãã¼ã«ãªã©ï¼ã®ãµã¤ãº
- GCã«ä½¿ç¨ããã¹ã¬ããæ°
ãã®ä¸è¦§ã ãã§ããã³ã³ããã¤ã¡ã¼ã¸ã«å¿ è¦ãªãªã½ã¼ã¹ã®å®ç¾©ã誤ãã¨ãGCã ä¸è¬çãªã¹ã¬ããæä½ã«é¢é£ããåé¡ãçºçãããã¨ããããã¾ãã
ããããåé¡ã¯æ ¹æ¬çã«ããããæ·±ãã®ã§ããJava 17ãå«ãç¾å¨ã®Javaã®ãã¼ã¸ã§ã³ã¯ãGCãã³ãã³ãã©ã¤ã³ã§æ示çã«æå®ããã¦ããªãå ´åãããã¤ãã®åçãã§ãã¯ãå®è¡ããã¨ã«ã´ããã¯ã¹ã®è¦³ç¹ããï¼èªåçã«ï¼ä½¿ç¨ããGCã決å®ãã¾ãã
ãã®åå ãçªãæ¢ããããã«ãOpenJDKã®ã½ã¼ã¹ã³ã¼ããè¦ã¦ã¿ã¾ããããå
·ä½çã«ã¯ãsrc/hotspot/share/gc/shared/gcConfig.cpp
ãã¡ã¤ã«ã« GCConfig::select_gc()
ã¨ãã C++ ã¡ã½ããããããGC ãæ示çã«é¸ã°ããªãéã GCConfig::select_gc_ergonomically()
ãå¼ã°ãããã¨ãåããã¾ãããã®ã¡ã½ããã®ã³ã¼ãã¯
void GCConfig::select_gc_ergonomically() { if (os::is_server_class_machine()) { #if INCLUDE_G1GC FLAG_SET_ERGO_IF_DEFAULT(UseG1GC, true); #elif INCLUDE_PARALLELGC FLAG_SET_ERGO_IF_DEFAULT(UseParallelGC, true); #elif INCLUDE_SERIALGC FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true); #endif } else { #if INCLUDE_SERIALGC FLAG_SET_ERGO_IF_DEFAULT(UseSerialGC, true); #endif } }
ãã®ã³ã¼ãçã®æå³ã¯ãC++ãã¯ã(Hotspotã®ã½ã¼ã¹ã®ãããã¨ããã§ä½¿ããã¦ãã)ã«ãã£ã¦å¤å°ä¸æçã«ãªã£ã¦ãã¾ãããåºæ¬çã«ã¯æ¬¡ã®ãããªãã¨ã«éç´ããã¾ããJava 11ã¨17ã§ã¯ãã³ã¬ã¯ã¿ãæå®ããªãã£ãå ´åã次ã®ã«ã¼ã«ãé©ç¨ããã¾ãã
- ãã·ã³ããµã¼ãã¯ã©ã¹ã§ããå ´åãGC ã¨ã㦠G1 ãé¸æãã¾ãã
- ãã·ã³ããµã¼ãã¯ã©ã¹ã§ãªãå ´åãGC ã¨ã㦠Serial ãé¸æãã¾ãã
ãã·ã³ããµã¼ãã¼ã¯ã©ã¹ãã©ãããå¤æããHotspotã®ã¡ã½ãã㯠os::is_server_class_machine()
ã§ããããã®ã³ã¼ããè¦ã¦ã¿ãã¨
// ããããµã¼ãã¼ã¯ã©ã¹ã®ãã·ã³ã®åä½å®ç¾©ã§ãã // ç©çCPUã2ã¤ä»¥ä¸ãã¡ã¢ãªã2GB以ä¸ãããã¨
ããã¯ãJava ã¢ããªã±ã¼ã·ã§ã³ããCPU ã 2 ã¤æªæºãã¡ã¢ãªã 2GB æªæºã¨æããããã·ã³ã¾ãã¯ã³ã³ããã§å®è¡ãããå ´åããããã¤æã«ç¹å®ã® GC ã¢ã«ã´ãªãºã ãæ示çã«é¸æããªãéããSerial ã¢ã«ã´ãªãºã ã使ç¨ããããã¨ãæå³ãã¾ãããã®çµæã¯ãé常ãG1ãããStop-the-Worldï¼STWï¼ãã¼ãºæéãé·ããªãããããã¼ã ãæããã®ã§ã¯ããã¾ããã
ãã®å¹æãå®éã«è¦ã¦ã¿ã¾ããããã¢ããªã±ã¼ã·ã§ã³ã®ä¾ã¨ãã¦ãAmazonã®Heapothesysããã¸ã§ã¯ãã®ä¸é¨ã§ããHyperAllocã使ç¨ãããã¨ã«ãã¾ãããã®ãã³ããã¼ã¯ãã¼ã«ã¯ã"ã¬ãã¼ã¸ã³ã¬ã¯ã¿ã®å¾ æ©æéã«å½±é¿ãä¸ããåºæ¬çãªã¢ããªã±ã¼ã·ã§ã³ç¹æ§ã模ããã人工çãªè² è· "ã§ãã
ç°¡åãªDockerfileããã³ã³ããã¤ã¡ã¼ã¸ãèµ·åãã¾ãã
FROM docker.io/eclipse-temurin:17 RUN mkdir /app COPY docker_fs/ /app WORKDIR /app CMD ["java", "-Xmx1G", "-XX:StartFlightRecording=duration=60s,filename=hyperalloc.jfr", "-jar", "HyperAlloc-1.0.jar", "-a", "128", "-h", "1024", "-d", "60"]
使ç¨ãã¦ããHyperAllocã®ãã©ã¡ã¼ã¿ã¯ããã¼ããµã¤ãºã1GBãã·ãã¥ã¬ã¼ã·ã§ã³ã®å®è¡æéã60ç§ãå²ãå½ã¦é度ã128MB/ç§ã§ããããã¯ã1ã¤ã®CPUã§ä½¿ç¨ããã¤ã¡ã¼ã¸ã§ãã
ã¾ãã2ã¤ã®CPUã®ã³ã³ããã§ä½¿ç¨ããããã«ãå²ãå½ã¦é度ã256MB/ç§ã«ãã以å¤ã¯åä¸ã®ã¤ã¡ã¼ã¸ãä½æãã¾ãã2çªç®ã®ã±ã¼ã¹ã§é«ãå²ãå½ã¦çãè¨å®ããã®ã¯ãHyperAllocã§å©ç¨å¯è½ãªCPUã®éãå¢ããã¦ã両æ¹ã®ãã¼ã¸ã§ã³ã§åãå²ãå½ã¦è² è·ãçµé¨ãããããã§ãã
JDK Flight Recorder (JFR)ã使ãã¨ãå ¨æéã®ãã°ãåå¾ã§ãã¾ããããã¯60ç§ã¨é常ã«çãã§ããããã®åç´ãªä¾ã§JVMã®å ¨ä½çãªåä½ãå®è¨¼ããã®ã«ååãªæéãããããã¾ãã
2ã¤ã®ã±ã¼ã¹ãæ¯è¼ãã¦ãã¾ãã
- 1 CPU, 2GB ã¤ã¡ã¼ã¸ã§ 128MB ã®å²ãå½ã¦é度 (Serial GC)
- 2 CPUs, 2GB ã¤ã¡ã¼ã¸ã§ 256MB ã®å²ãå½ã¦é度 (G1 GC)
ç§ãã¡ãè¦ãã2ã¤ã®GCãã¼ã¿ã¯ãå¥ã ã®ã±ã¼ã¹ã®ä¸æåæ¢æéã¨GCã®å¦çè½åï¼GCãå®è¡ããããã«è²»ããããç·CPUã¨ãã¦è¡¨ç¾ã ããï¼ã§ãã
ãã®ãµã³ãã«ã使ã£ã¦èªåã®ãã¼ã¿ã§å®é¨ãããå ´åã¯ãJFR Hacksã®GitHubãªãã¸ããªã«ã³ã¼ããããã¾ãããã®ããã¸ã§ã¯ãã¯Gunnar Morlingã®JFR Analyticsã«ä¾åãã¦ãããJFRã®è¨é²ãã¡ã¤ã«ãç §ä¼ããããã®SQL風ã®ã¤ã³ã¿ã¼ãã§ã¤ã¹ãæä¾ãã¦ãã¾ãã
注æ: ãã®å¾ã®ã°ã©ãã§ã¯ãå®è¡ã®ã¿ã¤ã ã¹ã¿ã³ãã¯VMèµ·åå¾ã®ããªç§ã«æ£è¦åããã¦ãã¾ãã
ã¾ããä¸æåæ¢æéããè¦ã¦ããã¾ããããå³1ã¯ã2ã¤ã®ã±ã¼ã¹ã®åè¨ä¼æ¢æéã示ãã¦ãã¾ãã
å³1ï¼1CPUã®å®è¡ã¯ã2CPUã®å®è¡ã«æ¯ã¹ã¦ãä¼æ¢æéã®åè¨ãé常ã«å¤ãã
ãã®çµæã¯ãG1 ã使ç¨ãããã¨ã®æ確ãªå©ç¹ã示ãã¦ãã¾ãããã¹ã¦ã®ã³ã¬ã¯ã·ã§ã³ã§ãä¸æåæ¢æéãå¤§å¹ ã«ç縮ããã¾ãããG1Newã³ã¬ã¯ã·ã§ã³ã¯ãã·ãªã¢ã«ã®è¥ãé åã®GCï¼DefNewã¨ãã¦ç¥ããã¦ããï¼ããã çãã§ããããããG1Newã®ã³ã¬ã¯ã·ã§ã³ã¯DefNewã®3åè¿ãããã¾ãã
ãã®æ¥å¢ã®çç±ã¯ãè¥ãé åã®GCã¯å¸¸ã«å®å ¨ã«STWã§ãããã¨ã§ãããªããªããå²ãå½ã¦ã¹ã¬ããï¼ã¢ããªã±ã¼ã·ã§ã³ã®ã¹ã¬ããï¼ã¯é«ãã¾ãã¯äºæ¸¬ã§ããªãå²ãå½ã¦é度ãæã¤å¾åãããã¾ããããã¯ãGCã¹ã¬ããã¨å²ãå½ã¦ã¹ã¬ããéã®CPUã®ç«¶äºã¯å¿ ãåã¦ã訳ã§ã¯ãªããã¨ãæå³ãã¾ã-è¥ãé åã®GCã®STWãã¼ãºãåãå ¥ããã§ããã ãçãä¿ã¤æ¹ãããã§ãããã
G1 ã¯ãå ¨é¨å®è¡ãããããããã¯å®è¡ããªããï¼all or nothingï¼ãã®ã³ã¬ã¯ã¿ã§ã¯ããã¾ããããã®åä½ã¯é åã«åºã¥ãã¦ãããããç¾å¨ã®å²ãå½ã¦é度ã«å ãããããã«ããã¤ãã®è¥ãé åãåéãããã®å¾ã¢ããªã±ã¼ã·ã§ã³ã¹ã¬ãããåèµ·åããããçãä¼æ¢ã®æ°ãå¢ããã¾ãããã®ãããªåå¼é¢ä¿(ãã¬ã¼ããªã)ã®å ¨ä½çãªå¹æã«ã¤ãã¦ã¯ãå¾ã»ã©è©³ãã説æãã¾ãã
å¤ãé åã®GCã§ã¯ããã®å¹æã¯ããã«é¡èã§ããG1Old ã¯å®éã«ç·ä¼æ¢æéãè½ã¡è¾¼ã¿ã¾ãããSerialOld ã¯å¤ãé åã®GCã§æããã«æ¥å¢ãã¾ããããã¯ãG1Oldã並è¡ã³ã¬ã¯ã¿ã¼ã§ãããããã³ã¬ã¯ã·ã§ã³ã®å®è¡æéã®å¤§é¨åã«ããã¦ãã¢ããªã±ã¼ã·ã§ã³ã¹ã¬ããã¨ä¸¦è¡ãã¦å®è¡ããã¦ããããã§ãã2CPUã®ä¾ã§ã¯ãG1Oldãå®è¡ããã¦ããéã1CPUã¯GCã«ã1CPUã¯ã¢ããªã±ã¼ã·ã§ã³ã¹ã¬ããã«ä½¿ç¨ããã¦ãã¾ãã
å³2ã¯ãåã³ã¬ã¯ã·ã§ã³ã®å®è¡çµéæéã示ããç·åæ¢æéã¨ã®å¯¾æ¯ã§ç¤ºãããã®ã§ãããããã¯ãG1Oldã®ä¸¦è¡æ§ã示ãã¦ãã¾ãã
å³2ï¼1CPUã®å®è¡ã¯ã2CPUã®å®è¡ã«æ¯ã¹ã¦GCã«è²»ããæéãé常ã«é·ã
æ¡ã®å®ãG1Oldã®ç·ä¼æ¢æéããçµéæéãã¨ã§è¦ãã¨æ大ã«ãªã£ã¦ãã¾ããã¾ããG1ã§ãSerialã§ããå¤ãé åã®GCã®æ°ã¯ã»ã¼åãã§ãããã¨ãç®è¦ã§ç¢ºèªã§ãã¾ãã
ãã®æç¹ã§åããããããããªããã²ã¨ã¤ã®æç½ãªçåãããã¾ããGCã®å®è¡ã«ããå ¨ä½çãªã³ã¹ãã¯ãCPUæéã§ã©ã®ãããã§ããããï¼ è¥ãé åã®G1ã³ã¬ã¯ã·ã§ã³ãè¥ãé åã®Serialã³ã¬ã¯ã·ã§ã³ãããå¤ããããG1ã使ç¨ããå ¨ä½çãªCPUæéã¯ããé«ãã¨ããå¯è½æ§ã¯ããã¾ãããï¼ãã®è³ªåã«çããããã«ã2ã¤ã®ã³ã¬ã¯ã¿ã¼ã®GCã«è²»ããããç´¯ç©æéã示ãå³3ãè¦ã¦ãã ããã
å³3ï¼2CPUã®å®è¡ã¯ã1CPUã®å®è¡ãããå ¨ä½ã¨ãã¦GCã«è²»ããæéãé·ããã2åã®æéã¯ããããªãã
ä¸è¦ããã¨ãG1ãSerialãããCPUãå¤ã使ã£ã¦ããããã«è¦ãã¾ããããããG1å®è¡ã¯2ã¤ã®CPUã使ç¨ãã2åã®å²ãå½ã¦çã§å¦çãã¦ãããã¨ãå¿ãã¦ã¯ããã¾ãããã¤ã¾ããCPUåä½ããããã¯å²ãå½ã¦GBåä½ã§è¦ãã¨ãG1ã¯Serialãããã¾ã å¹çãè¯ãã¨ãããã¨ã§ãã
å ¨ä½ã¨ãã¦ãããå°ããªã³ã³ããã®è¦ããä¸ã®é åã«ãããããããã»ã¨ãã©ãã¹ã¦ã®å ´åã«ããã¦ã2ã¤ã®CPUã¨2GBã®ã¡ã¢ãªãæã¤ã³ã³ããã§Javaããã»ã¹ãå®è¡ããG1ã®ä¸¦è¡GCã«å©ç¨å¯è½ãªãªã½ã¼ã¹ãå©ç¨ãããæ¹ãè¯ãã¨ãããã¨ã§ãã
ã¾ã¨ãã¨ä»å¾ã«ã¤ãã¦
ãã®ããã¡ãã®ä¾ã§å¹æãã¯ã£ããåãã£ãã¨ããã§ã1ã¤å¤§ããªçåãæ®ãã¾ããããã®å¹æã¯ãæ¬çªç¨ã®ã³ã³ããã§ã¯ã©ã®ããã«çºæ®ãããã®ã§ããããï¼
çãã¯ãJavaã®ãã¼ã¸ã§ã³ã¨ã«ã¼ãã«ã®ãµãã¼ãã«ä¾åãã¾ããç¹ã«ãcgroupsã¨å¼ã°ããç¹å®ã®ã«ã¼ãã«APIãv1ãv2ã®ã©ã¡ãã§ãããã«ããã¾ãã
ãã®ã·ãªã¼ãºã®ç¬¬2åã§ã¯ãSeverin GehwolfããHotspotãã©ã®ããã«ã³ã³ããã®ããããã£ãæ¤åºããããã«åºã¥ãã¦èªåãµã¤ãºã決å®ããã®ãããã®è©³ç´°ãæ·±ãæãä¸ãã¦èª¬æãã¾ããã¾ããJavaã¢ããªã±ã¼ã·ã§ã³ã®ã³ã³ããåã«é¢ããMicrosoftã®æè¿ã®è¨äºãã覧ã«ãªã£ã¦ã¿ã¦ãã ããã