8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Javaバージョン毎におけるkubernetes (GKE)上でのメモリ、CPU認識のデフォルト動作の違い

Last updated at Posted at 2018-07-31

はじめに

Java 8においても、
[Oracle Blogs 日本語のまとめ - [Java] Java SE support for Docker CPU and memory limits] (https://orablogs-jp.blogspot.com/2017/05/java-se-support-for-docker-cpu-and.html)
の記事から、8u131以降はある程度 container.resource.limit.cpu、container.resource.limit.memoryを見て上手い事やってくれるのかな?
と思いきや、いまいちな挙動だったので、kubernetesで動かした際のjava8、java10、java11(ea)でのCPUの認識、及びメモリサイズの確保部分について調べてみました。

特に、GCの並列実行(スレッド数)や、各種並列スレッドのプール数等にも影響がある、 Runtime#availableProcessorsの動きがバージョンで変わるのか?という部分が
https://bugs.openjdk.java.net/browse/JDK-8140793
を見ても、2018/7/31時点でまだfixedVersionが出ていないのでどのバージョンでもまともに動かないのかどうかが気になった次第です。

結論

  • kubernetesでJavaアプリケーションを動作させる際、CPU、メモリを正しく認識させたいならjava10以降ならちゃんと認識してくれる。
  • java8でもメモリはXmx、Xmsなどで制御可能。
  • java8ではRuntime#availableProcessorsは正しく制限かける事はできないが、GCThread等は制御可能。

前提Javaアプリケーション

適当なSpring Boot アプリケーションを動かしてそのmetrics情報と、java -XX:+PrintGCDetails -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions をcontainer上で動かした際の情報を確認します。

Spring Bootのアプリケーションは、
https://github.com/h-r-k-matsumoto/spring-boot-sample
をベースとして、それぞれ下記のように変更しています。また、cointainerに対するリソース割当は、下記のようになります。

020_deployments.yml
        resources:
          requests:
            cpu: 150m
            memory: 512Mi
          limits:
            cpu: 900m
            memory: 512Mi

deploymentsの全文は、
https://github.com/h-r-k-matsumoto/spring-boot-sample/blob/master/kubernetes/020_deployments.yml
です。

java8 (no cgroup option)

pom.xmlのfrom imageを下記に変更します。特にJavaオプションでは何も制御しません。デフォルトのままです。

pom.xml
  <image>openjdk:8u171-jre-alpine</image>

java8

pom.xmlのfrom imageを下記に変更します。

pom.xml
  <image>openjdk:8u171-jre-alpine</image>

更に、下記jvmFlagオプションを追加します。ポイントは、 UseCGroupMemoryLimitForHeap です。
後は・・・私がいつもdocker 環境で動かす際につけているものです。

pom.xml
  <jvmFlag>-XX:+UnlockExperimentalVMOptions</jvmFlag>
  <jvmFlag>-XX:+UseCGroupMemoryLimitForHeap</jvmFlag>
  <jvmFlag>-XX:ParallelGCThreads=1</jvmFlag>
  <jvmFlag>-XX:CICompilerCount=2</jvmFlag>
  <jvmFlag>-Djava.util.concurrent.ForkJoinPool.common.parallelism=1</jvmFlag>

java10

pom.xmlのfrom imageを下記に変更します。オプションは指定無しです。

pom.xml
  <image>openjdk:10-jre-slim</image>

java11 (ea)

pom.xmlのfrom imageを下記に変更します。オプションは指定無しです。

pom.xml
  <image>openjdk:11-jre-slim</image>

計測内容

[Spring Boot Actuatorのmetrics] (https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html) 機能と、

PrintFlagsFinal
 kubectl exec {pod-name} -- java -XX:+PrintGCDetails -XX:+PrintFlagsFinal -XX:+UnlockExperimentalVMOptions

を実行して取得した情報を利用します。

Spring Boot Actuator - metrics

system.cpu.count

http://pod-ip:port/actuator/metrics/system.cpu.count
で取得します。Runtime#availableProcessors の実行結果です。
ソースはmicrometer - ProcessorMetrics.java

jvm.memory.max (heap)

http://pod-ip-port/actuator/metrics/jvm.memory.max?tag=area:heap
で取得します。ヒープ領域の最大サイズです。
ソースは、micrometer - JvmMemoryMetrics.javaMemoryUsage#getMax の結果です。

PrintFlagsFinal結果

MaxHeapSize

最大ヒープ管理領域のサイズです。jvm.memory.maxと同じになる・・・はず。

UseParallelGC

GCを並列実行するかどうかです。
参考:https://docs.oracle.com/javase/jp/8/docs/technotes/guides/vm/gctuning/collectors.html

ParallelGCThreads

パラレルGCの際のスレッド数です。

計測結果

実行するノードのspecは、vCPUx2、メモリ7.5GBです。

java version system.cpu.count jvm.memory.max(heap):MiB MaxHeapSize:MiB UseParallelGC ParallelGCThreads
java 11(ea) 1 123.75 128.00 false 0
java 10 1 123.75 128.00 false 0
java 8 2 120.00 128.00 true 2
java 8 (no cgroup option) 2 1,857.00 1,870.00 true 2

※java 8でparallelになってしまっているのは、-XX:+UseSerialGC のオプションでserialに変更可能。というか -XX:ParallelGCThreads=1 が効いていない…。

java11、java10は、特にオプション指定をしなかった場合は、containersに割り当てられたメモリサイズの 512Mi から正しく計算され、MaxRAMFraction=4となるため、512/4 = 128 となっていました。
また、CPUに関しても、900mとしましたが、1コア分として判定されています。
java11、java10は、XmxやらXmsは指定せずとも、container上で正しく動きそうです。

java8の場合は、メモリに関しては制御可能です。ただし、CPU数に関しては上手い事手出しができないっぽいので…  Runtime#availableProcessors から計算していてリソース確保している部分は、都度システムプロパティ等で設定した方がよさそうです。

jvm.memory.max(heap)と、MaxHeapSizeで多少の誤差が出てるのは・・・気にしないです!
もし「このようなオプションを指定した方が良い」、「ここ、間違ってるよ」とかあればご指摘お願いします。

参考

8
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?