Fargate上のJVMからCPUを認識するまで〜正しく認識されないCPUの謎を追え〜金川 祐太郎株式会社ディー・エヌ・エー
View Slide
2自己紹介金川 祐太郎● 所属: 株式会社ディー・エヌ・エー● twitter: @orekyuu● 最近の悩み: コロナ禍に入ってから太ってしまった久しぶりに登壇で顔を出したらTwitterで「顔のアス比かわったね」
3本日のゴール● 今回の事例を例に、JVMがどのようにCPU数を認識しているかを知る非ゴール: ECSでJavaアプリケーションを使うためのコツや知見OpenJDKのコードを読むためのきっかけになれば幸いです
事例の紹介
5環境の紹介1● Quarkus: 2.9.2● JDK: amazon corretto 17● quarkus-container-image-jibでビルドしたimageをECS fargateへdeploy
6GCのアルゴリズムを指定せず動かすとSerial GCになっている2● 負荷試験でJFRの記録をとったところ、SerialGCが使われていることが分かった● ECS Taskのcpuの指定は2048になっていて、G1 GCが使われるはず
7目次OpenJDKのGCに関する登場人物OpenJDKが使うGC選択の流れAvailableProcessorsの検出の流れ123
8OpenJDKのGCに関する登場人物
9OpenJDKのディレクトリの構造● src/hotspot以下にosやcpuアーキテクチャ毎の実装が書かれており、shareは共通の実装● share以下は機能ごとにディレクトリが掘られている1
10登場人物1Arguments GCConfig GCArgumentsSerialArguments SerialArgumentsinitializeGCの決定 GCアルゴリズムごとの引数GCアルゴリズムごとにサブクラスを持つCollectedHeapcreateHeap
11登場人物1Arguments GCConfig GCArgumentsSerialArguments SerialArgumentsinitializeGCの決定 GCアルゴリズムごとの引数GCアルゴリズムごとにサブクラスを持つCollectedHeapcreateHeap
12OpenJDKが使うGC選択の流れ
13GCアルゴリズムの決定1
14GCアルゴリズムの決定1
15GCアルゴリズムの決定1起動オプションでGCが明示的に指定されていない
16GCアルゴリズムの決定1サーバークラスマシンなら G1GCそうでないならSerialGCを選んでいる
17GCアルゴリズムの決定1active_processor_countが2以上physical_memoryが約2GB以上右辺の変数は直前で宣言している
18jcmd VM.infoしてみる2initial active 1 になっている?
AvailableProcessorsの検出の流れ
20active_processor_countの取得1os::active_processor_countはosごとに実装が異なる今回のイメージでは linuxの実装になる
21active_processor_countの取得1-XX:ActiveProcessorCountが指定されている場合
22active_processor_countの取得1コンテナのときはこちらの処理に入る
※ここから2022/08頃のコードですOpenJDKのmasterを見ていましたが、変更が入って処理の内容が変わっているためです
24active_processor_countの取得1CgroupSubsystemとは?
25寄り道: cgroups1● linuxの機能で、プロセスの利用するリソースに制限をかけるもの● dockerではcgroupsを活用しているらしく、コンテナ対応のコードでcgroupsの名前が出てきた
26active_processor_countの取得1どうやらDockerコンテナのサポートっぽい
27active_processor_countの取得1share / 1024がshare_countになる
28active_processor_countの取得1最終的にcpu_countとlimit_countの小さい値がactive_processor_count
29active_processor_countの取得1これらのログを確認したい
30ログの確認2● -Xlogオプションを使う○ 今回の場合はjava -Xlog:os+container=trace -versionをECSのコンテナ内で実行して検証
31ログの確認2CPU Sharesが2になっている?
32active_processor_countの取得1share / 1024がshare_countになる
33原因を知る3● 「詳解: Amazon ECS による CPU とメモリのリソース管理」という記事を読む
34原因を知る3コンテナにCPUユニットを設定しない場合、 2を設定します
35原因を知る3● ECSにはTask DefinitionとContainer Definitionの両方にCPUの制限をつけられる● JVMが見ているのはContainer DefinitionのCPU制限で、指定をしない場合は2になる
36まとめ3● ECSにはTask DefinitionとContainer Definitionの両方にCPU制限があり、JVMが見るのはContainerの方なので必ず宣言しよう● GCは明示的に指定しない場合、意図しないGCになる場合があるので明示的に宣言しておくと安心● -Xlogオプションでログを出力できるので、デバッグする際には活用してみよう● JDKのコードを読むのは怖くない!みんな読もう!