$30 off During Our Annual Pro Sale. View Details »

JavaアプリをKubernetesで動かすためのチューニングガイド / A tuning guide for running java apps on Kubernetes

hhiroshell
January 19, 2022

JavaアプリをKubernetesで動かすためのチューニングガイド / A tuning guide for running java apps on Kubernetes

#ochacafe Season 5 #1 のLTセッションの資料です。
https://ochacafe.connpass.com/event/232810/

hhiroshell

January 19, 2022
Tweet

More Decks by hhiroshell

Other Decks in Technology

Transcript

  1. KubernetesでJavaアプリケーションを 動かすためのチューニングガイド 〜 LT編 @hhiroshell 1

  2. 宣伝 • 感染対策をしっかりやって遊舎⼯房に⾏きましょう 2 遊舎⼯房さんの店舗はこちら→ ↓現在の@hhiroshellのキーボードたち #crkbd ⾃⼰紹介 @hhiroshell 早川

    博 (はやかわ ひろし) • Cloud Nativeなインフラを開発 するエンジニア。 Yahoo Japan Corporation 所属 • エンジニアコミュニティ 「Cloud Native Developers JP」 オーガナイザー • Developers Summit 2018 Japan Container Days 12.18 CloudNative Days Tokyo 2019, 2020, 2021 • ⾃作キーボード沼 BMEK
  3. ⽬次 1. イントロダクション 2. Kubernetesのリソース管理機能 3. Kubernetesのリソース管理を踏まえてJavaのチューニングを考える 4. まとめ 3

  4. ⽬次 1. イントロダクション 2. Kubernetesのリソース管理機能 3. Kubernetesのリソース管理を踏まえてJavaのチューニングを考える 4. まとめ 4

  5. CloudNative時代のJavaエンジニアの悩み • Kubernetesのリソース設定は難しい…。ぶっちゃけ雰囲気で設定して いる。RequestsとLimits…?なんで2種類あるん? • Java(JVM)のチューニングするの(昔から)難しくないですか。いま だによくわかりません。変な設定したら怒られそうだし。 • つまりKubernetes x

    Javaはとても難しい。 Ϥγʂ 5
  6. 両⽅わかったらとても重宝されると思うんだ • というわけでやっていきましょうー。 6

  7. ⽬次 1. イントロダクション 2. Kubernetesのリソース管理機能 3. Kubernetesのリソース管理を踏まえてJavaのチューニングを考える 4. まとめ 7

  8. Kubernetesにおけるリソース設定 • RequestsとLimitsとがある • Requests – コンテナのために最低限確保されるリソース • CPU /

    Memory / hugepages / ephemeral-storage • Requestsに指定したリソースを実際に使えることが保証 される • Limits – コンテナが利⽤できる最⼤のリソース • CPU / Memory / hugepages / ephemeral-storage • Nodeに空きがあるときに使⽤できる最⼤のリソース量 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx:latest resources: requests: cpu: 0.5 memory: 1G limits: cpu: 1 memory: 2G 実利⽤量 Requests Limits 8
  9. RequestsとLimitsにまつわるいろいろな挙動 – 1/3 • Podが起動するとき – コンテナのRequestsの合計がNodeの全体を超えないように、配置先のNodeが選ばれる – Nodeに余裕があってもRequestsの値で判定される •

    起動しさえすればコンテナはRequestsまでリソースが使える NodeのCPU or Memory全体 Requestsの合計がNodeを超えないのでデプロイOK! 9
  10. RequestsとLimitsにまつわるいろいろな挙動 – 2/3 • リソースの実使⽤量が⼤きくなってNodeが混んできたとき – コンテナ同⼠でリソースの消費量がバランスされる – QoSの優先度に従ってPodのEvictが起きる(他のNodeに退避させられる) •

    Nodeに空きが無ければLimitsまでのリソースが使えない NodeのCPU or Memory全体 QoSのランクが低いPodから 優先的にEvictされる 10
  11. 【参考】QoS(Quality of Service) Class • PodのEvictされやすさはQoS Classによって決まる • Guaranteed: –

    全てのコンテナの、CPUとMemoryのLimitsとRequestが設定されており、 Limits=Requestsとなっている場合にこれになる – Limitsのみ設定するとRequestsに同じ値が設定されるため、CPUと MemoryのLimitsのみを指定した場合もGuaranteedになる • Burstable: – Guaranteed、BestEffortに当てはまらない場合これになる • BestEffort: – 全てのコンテナでLimitsとRequestが設定されていない場合にこれになる Evict されづらい Evict され易い 11
  12. RequestsとLimitsにまつわるいろいろな挙動 – 3/3 • Limitsを超えたリソースを使おうとしたとき – CPUの場合:スロットリング • CPUの利⽤量がLimitの値を超えない状態で動作を継続 –

    メモリの場合:OOMKill • コンテナがKillされ、結果としてPodが再起動される • Nodeに余裕があってもLimitsを超えるリソースは使えない NodeのCPU or Memory全体 Limitsを超えないように 制御される 12
  13. ⽬次 1. イントロダクション 2. Kubernetesのリソース管理機能 3. Kubernetesのリソース管理を踏まえてJavaのチューニングを考える 4. まとめ 13

  14. Kubernetesのリソース管理とJavaアプリの関係 • Javaアプリケーションが消費するリソースは下図のリソースの実使 ⽤量に当たる(当たり前のことではありますが…) – ⼀部のJVMパラメータはLimitsの設定値から⾃動調整される – 実使⽤量がRequestsやLimitsに収まるように、JVMをチューニングしたり(特に メモリ)、レプリカ数を増やして1レプリカあたりの負荷を下げたりする Requests

    Limits Javaアプリケーションが 消費するリソース 14
  15. Limitsの設定から影響を受けるJVMの挙動 • Limitsの設定値を認識してJVMが⼀部の挙動を⾃動的に変える • CPU – Limitsの設定値がコンテナの --cpu-shares にマッピングされる。これをJVMが認 識して動作する

    – 結果として、Runtime.availableProcessors()の返り値や、ForkJoinプール、スレッ ドプールの割当量が変わる。これらに依存して挙動を変えているライブラリ やフレームワークも影響を受ける (e.g., core.async, ElasticSearch, Netty) • メモリ – JVMのヒープメモリが、Limitsに対してエルゴノミクスによって決定される – これに従ってGCアルゴリズム等も決まる 15
  16. Javaアプリケーションが使うメモリの内訳 ① ヒープメモリ – ご存知ヒープメモリ。デフォルトではLimitsの値から動的に決定される(エルゴノミクス) ② スレッドスタック – 1スレッドごとに確保されるメモリ領域。デフォルトは1024K /

    Thread ③ コードキャッシュ – JITコンパイラによりコンパイルされたコードのキャッシュが保持される領域。デフォルトでは約240MB 消費メモリ合計 = ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ + ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ 16
  17. Javaアプリケーションが使うメモリの内訳 ④ メタスペース – クラスメタデータが配置される領域。デフォルトでは無制限 ⑤ ダイレクトメモリ – New I/Oダイレクトバッファで使う領域。デフォルトでは無制限。アプリの利⽤に合わせて適宜追加で確保

    ⑥ ネイティブメモリ – ネイティブメソッドの実⾏に伴って消費される領域。上限値を設定することはできない 消費メモリ合計 = ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ + ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ 17
  18. ヒープメモリを調整しよう • デフォルトに任せるとヒープメモリの最⼤値がResource Limitsの20〜 30%となる(コンテナでない環境ならこれで良かったのかな?)。これだと多くの場合 Requests / Limitsに設定したメモリを使い切れない • -XX:MaxRAMPercentage=50.0

    のように設定するとResource Limitsに対 する割合で指定できる Requests Limits ヒープメモリの上限に当たってこれ以上使えない 18
  19. 設定例 19 apiVersion: v1 kind: Pod metadata: name: openjdk8 spec:

    containers: - image: openjdk:11-jdk-slim name: openjdk # ...(snip)... resources: requests: memory: 256Mi cpu: 0.25 limits: memory: 1Gi cpu: 1 env: - name: JAVA_TOOL_OPTIONS value: “-XX:MaxRAMPercentage=50.0 -XX:MaxMetaspaceSize=128M -XX:MaxDirectMemorySize=10M"
  20. チューニング時に意識すべきメモリ領域 • スレッドスタック、コードキャッシュは意外と消費が多いので、 ヒープメモリを除いた残りでこれが収まるように注意 – スレッドスタック: • Spring Bootでは最⼤コネクション数分のスレッド(デフォルト: 200)が⽣成される。

    1024K * 200 = 205M に、他のスレッド分が加わる – コードキャッシュ: • デフォルトでは最⼤約240M • コンテナではそれほど⼤きいメモリを割り当てないことが多い。 Limitsが1GBならヒープは50%程度にしておくと安全 • 実際は測って決める 20
  21. もっと本格的なチューニングは…。 • 実物で計測しながら各パラメータを調整して下さい…。m(_ _)m – > 推測するな、計測せよ c.f. https://qiita.com/e99h2121/items/e8f899756b21b0414835 •

    CloudFoundryのJava Buildpack Memory Calculatorも参考にできる – メモリパラメータの⾃動計算アルゴリズム公開されている 消費メモリ合計 = ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ + ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ 21
  22. ⽬次 1. イントロダクション 2. Kubernetesのリソース管理機能 3. Kubernetesのリソース管理を踏まえてJavaのチューニングを考える 4. まとめ 22

  23. まとめ • KubernetesのPodにはResource Limits / Requestsを設定できる – Requests: コンテナのために最低限確保されるリソース –

    Limits: コンテナが利⽤できる最⼤のリソース • JVMはResource Limitsの設定値を受けて⼀部パラメータを⾃動調整す る • ヒープメモリはデフォルトに任せると⼗分にメモリを使えないので、 最⼤値を引き上げるのがおすすめ • 実際のチューニングは実物で計測しながらやりましょう 23
  24. Fin. 24

  25. Appendix. 参考⽂献 25

  26. 【参考⽂献】 • Resource Management for Pods and Containers – https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

    • Resource Requests and Limits Under the Hood: The Journey of a Pod Spec – https://speakerdeck.com/inductor/resource-requests-and-limits-under-the-hood-the- journey-of-a-pod-spec • Understanding CPU throttling in Kubernetes to improve application performance – https://speakerdeck.com/daikurosawa/understanding-cpu-throttling-in-kubernetes-to- improve-application-performance-number-k8sjp • Better Containerized JVMs in JDK10 – http://blog.gilliard.lol/2018/01/10/Java-in-containers-jdk10.html • CloudFoundry Java Buildpack Memory Calculator – https://github.com/cloudfoundry/java-buildpack-memory-calculator 26