Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

  9. RequestsとLimitsにまつわるいろいろな挙動 – 1/3
    • Podが起動するとき
    – コンテナのRequestsの合計がNodeの全体を超えないように、配置先のNodeが選ばれる
    – Nodeに余裕があってもRequestsの値で判定される
    • 起動しさえすればコンテナはRequestsまでリソースが使える
    NodeのCPU or Memory全体
    Requestsの合計がNodeを超えないのでデプロイOK!
    9

    View full-size slide

  10. RequestsとLimitsにまつわるいろいろな挙動 – 2/3
    • リソースの実使⽤量が⼤きくなってNodeが混んできたとき
    – コンテナ同⼠でリソースの消費量がバランスされる
    – QoSの優先度に従ってPodのEvictが起きる(他のNodeに退避させられる)
    • Nodeに空きが無ければLimitsまでのリソースが使えない
    NodeのCPU or Memory全体
    QoSのランクが低いPodから
    優先的にEvictされる
    10

    View full-size slide

  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

    View full-size slide

  12. RequestsとLimitsにまつわるいろいろな挙動 – 3/3
    • Limitsを超えたリソースを使おうとしたとき
    – CPUの場合:スロットリング
    • CPUの利⽤量がLimitの値を超えない状態で動作を継続
    – メモリの場合:OOMKill
    • コンテナがKillされ、結果としてPodが再起動される
    • Nodeに余裕があってもLimitsを超えるリソースは使えない
    NodeのCPU or Memory全体
    Limitsを超えないように
    制御される
    12

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. Limitsの設定から影響を受けるJVMの挙動
    • Limitsの設定値を認識してJVMが⼀部の挙動を⾃動的に変える
    • CPU
    – Limitsの設定値がコンテナの --cpu-shares にマッピングされる。これをJVMが認
    識して動作する
    – 結果として、Runtime.availableProcessors()の返り値や、ForkJoinプール、スレッ
    ドプールの割当量が変わる。これらに依存して挙動を変えているライブラリ
    やフレームワークも影響を受ける (e.g., core.async, ElasticSearch, Netty)
    • メモリ
    – JVMのヒープメモリが、Limitsに対してエルゴノミクスによって決定される
    – これに従ってGCアルゴリズム等も決まる
    15

    View full-size slide

  16. Javaアプリケーションが使うメモリの内訳
    ① ヒープメモリ
    – ご存知ヒープメモリ。デフォルトではLimitsの値から動的に決定される(エルゴノミクス)
    ② スレッドスタック
    – 1スレッドごとに確保されるメモリ領域。デフォルトは1024K / Thread
    ③ コードキャッシュ
    – JITコンパイラによりコンパイルされたコードのキャッシュが保持される領域。デフォルトでは約240MB
    消費メモリ合計 =
    ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ +
    ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ
    16

    View full-size slide

  17. Javaアプリケーションが使うメモリの内訳
    ④ メタスペース
    – クラスメタデータが配置される領域。デフォルトでは無制限
    ⑤ ダイレクトメモリ
    – New I/Oダイレクトバッファで使う領域。デフォルトでは無制限。アプリの利⽤に合わせて適宜追加で確保
    ⑥ ネイティブメモリ
    – ネイティブメソッドの実⾏に伴って消費される領域。上限値を設定することはできない
    消費メモリ合計 =
    ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ +
    ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ
    17

    View full-size slide

  18. ヒープメモリを調整しよう
    • デフォルトに任せるとヒープメモリの最⼤値がResource Limitsの20〜
    30%となる(コンテナでない環境ならこれで良かったのかな?)。これだと多くの場合
    Requests / Limitsに設定したメモリを使い切れない
    • -XX:MaxRAMPercentage=50.0 のように設定するとResource Limitsに対
    する割合で指定できる
    Requests
    Limits
    ヒープメモリの上限に当たってこれ以上使えない
    18

    View full-size slide

  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"

    View full-size slide

  20. チューニング時に意識すべきメモリ領域
    • スレッドスタック、コードキャッシュは意外と消費が多いので、
    ヒープメモリを除いた残りでこれが収まるように注意
    – スレッドスタック:
    • Spring Bootでは最⼤コネクション数分のスレッド(デフォルト: 200)が⽣成される。
    1024K * 200 = 205M に、他のスレッド分が加わる
    – コードキャッシュ:
    • デフォルトでは最⼤約240M
    • コンテナではそれほど⼤きいメモリを割り当てないことが多い。
    Limitsが1GBならヒープは50%程度にしておくと安全
    • 実際は測って決める
    20

    View full-size slide

  21. もっと本格的なチューニングは…。
    • 実物で計測しながら各パラメータを調整して下さい…。m(_ _)m
    – > 推測するな、計測せよ c.f. https://qiita.com/e99h2121/items/e8f899756b21b0414835
    • CloudFoundryのJava Buildpack Memory Calculatorも参考にできる
    – メモリパラメータの⾃動計算アルゴリズム公開されている
    消費メモリ合計 =
    ① ヒープメモリ + ② スレッドスタック + ③ コードキャッシュ +
    ④ メタスペース + ⑤ ダイレクトメモリ + ⑥ ネイティブメモリ
    21

    View full-size slide

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

    View full-size slide

  23. まとめ
    • KubernetesのPodにはResource Limits / Requestsを設定できる
    – Requests: コンテナのために最低限確保されるリソース
    – Limits: コンテナが利⽤できる最⼤のリソース
    • JVMはResource Limitsの設定値を受けて⼀部パラメータを⾃動調整す

    • ヒープメモリはデフォルトに任せると⼗分にメモリを使えないので、
    最⼤値を引き上げるのがおすすめ
    • 実際のチューニングは実物で計測しながらやりましょう
    23

    View full-size slide

  24. Appendix.
    参考⽂献
    25

    View full-size slide

  25. 【参考⽂献】
    • 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

    View full-size slide