未分類

CentOS7とJavaの性能検証用環境の構築(その6:性能計測編)

性能計測の実行

やっと環境がほぼ整いました。
それではJmeterでCentOSに負荷をかけて、サーバーで実行されるKernelの情報を取得しましょう。

以下の準備が整っている状態で実行します。
・サーバーが起動していること
・perf-map-agentがアタッチされていること
・Jmeterが設定されていること。

perf-map-agentの設定はこれから行います。

①perf-map-agentをアタッチ

Linuxでjavaを実行した際には、実行時のアドレスとメソッド名の対応が読み取れないんですね。読み取ることができるようにするためにperf-map-agentというツールを使用します。

[root@localhost ~]# chmod 777 ~
[root@localhost ~]# mkdir -m 777 work
[root@localhost ~]# ll | grep work
drwxrwxrwx. 2 root root    6  9月 15 21:26 work
[root@localhost ~]# cd work
[root@localhost work]# git clone https://github.com/jrudolph/perf-map-agent.git
Cloning into 'perf-map-agent'...
remote: Enumerating objects: 438, done.
remote: Total 438 (delta 0), reused 0 (delta 0), pack-reused 438
Receiving objects: 100% (438/438), 127.74 KiB | 0 bytes/s, done.
Resolving deltas: 100% (208/208), done.

perf-map-agentのサイトを見ると、cmakeコマンドを利用して、ビルドを行うよう書かれています。cmakeコマンドのインストールが必要になります。
ただし、cmakeコマンドを実行するために、cおよびc++のコンパイラが必要になりますので、こちらも事前にインストールしておきます。
c++のコンパイラであるg++のパッケージ、「gcc-c++」をインストールします。
このパッケージのインストールで、cのコンパイラであるgccも依存性解決のため、一緒にインストールされます。

[root@localhost perf-map-agent]# yum install gcc-c++
   :
依存性関連をインストールしました:
  cpp.x86_64 0:4.8.5-39.el7                               gcc.x86_64 0:4.8.5-39.el7
  glibc-devel.x86_64 0:2.17-307.el7.1                     glibc-headers.x86_64 0:2.17-307.el7.1
  kernel-headers.x86_64 0:3.10.0-1127.19.1.el7            libstdc++-devel.x86_64 0:4.8.5-39.el7

完了しました!

c、c++のコンパイラをインストールできたら、cmakeをインストールします。

[root@localhost work]# yum install cmake

んで、さっそくperf-map-agentをビルドします。

[root@localhost perf-map-agent]# cmake .
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- JNI_INCLUDE_DIRS=/usr/lib/jvm/java/include;/usr/lib/jvm/java/include/linux;/usr/lib/jvm/java/include
-- JNI_LIBRARIES=/usr/lib/jvm/jre/lib/amd64/libjawt.so;/usr/lib/jvm/jre/lib/amd64/server/libjvm.so
-- JAVA_INCLUDE_PATH=/usr/lib/jvm/java/include
-- JAVA_INCLUDE_PATH2=/usr/lib/jvm/java/include/linux
-- Configuring done
-- Generating done
-- Build files have been written to: /root/work/perf-map-agent

[root@localhost perf-map-agent]# make
Scanning dependencies of target attach-main
[ 20%] Building Java objects for attach-main.jar
[ 40%] Generating out/CMakeFiles/attach-main.dir/java_class_filelist
[ 60%] Creating Java archive attach-main.jar
[ 60%] Built target attach-main
Scanning dependencies of target perfmap
[ 80%] Building C object CMakeFiles/perfmap.dir/src/c/perf-map-agent.c.o
[100%] Building C object CMakeFiles/perfmap.dir/src/c/perf-map-file.c.o
Linking C shared library out/libperfmap.so
[100%] Built target perfmap

ビルドできたらglassfishのプロセスにアタッチします。

[root@localhost perf-map-agent]# ps -u glassfish
  PID TTY          TIME CMD
 3207 pts/1    00:00:00 bash
 3271 pts/1    00:00:30 java

## glassfishで実行しているGlassgishのPIDは3271なので、、、

[root@localhost perf-map-agent]# cd bin
[root@localhost bin]# ./create-java-perf-map.sh 3271

これでperf実行時に実行結果でメソッド名を出してくれるようになります。
(やらないとjava実行部分がperf-{pid}.mapみたいに出力されます。)

②FlameGraphの取得

NetflixのBrendan Greggさんが作成した、perfコマンドのプロファイルを可視化してくれるツールを取得します。

## 自分のホーム配下のworkディレクトリへ移動
[root@localhost bin]# cd ~/work
## ディレクトリの状態を確認
[root@localhost work]# ll
合計 0
drwxr-xr-x. 5 root root  59  9月 15 23:52 JavaPerformanceTuning
drwxr-xr-x. 7 root root 225  9月 15 23:50 perf-map-agent
## FlameGraphをGitで取得
[root@localhost work]# git clone https://github.com/brendangregg/FlameGraph.git
Cloning into 'FlameGraph'...
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1067 (delta 0), reused 0 (delta 0), pack-reused 1066
Receiving objects: 100% (1067/1067), 1.87 MiB | 1.62 MiB/s, done.
Resolving deltas: 100% (612/612), done.
## ダウンロード結果を確認
[root@localhost work]# ll
合計 4
drwxr-xr-x. 7 root root 4096  9月 28 15:09 FlameGraph
drwxr-xr-x. 5 root root   59  9月 15 23:52 JavaPerformanceTuning
drwxr-xr-x. 7 root root  225  9月 15 23:50 perf-map-agent
## ダウンロードしたFlameGraphのディレクトリに移動
[root@localhost work]# cd FlameGraph
[root@localhost FlameGraph]#

この状態で以降の作業を行います。

③Jmeterの実行

Javaの性能計測するうえで、Jmeterのボタンを押したところでの計測はまだちょっと早いです。計測するにあたってウォームアップを行う必要があります。
Javaはコンパイラ型の言語ですが、実行時にすべてのコードをコンパイルするのではなく、実行に必要なコードだけをコンパイルする仕様になっています。これはJITコンパイラと呼ばれていますが、Java起動直後は最適なコンパイル状態となるまで、何回か命令を実行する必要があり、それがいわゆるウォームアップと呼ばれるものです。
先ほどのJmeterのGraph Resultsで見ると下記のようなグラフになっているのはそのためです。

画像に alt 属性が指定されていません。ファイル名: image-29.png

今回はJmeterのThread Groupの設定を以下のようにします。
サーバーによっては負荷が高すぎてハングアップし、レスポンスが返ってこなくなってしまうので、必要に応じて下げたり上げたりするといいでしょう。

画像に alt 属性が指定されていません。ファイル名: image-30.png

今回は残りの60秒での状態をプロファイリング(測定)します。

Jmeterで実行開始して、60秒が経過したらサーバー側で以下の通りコマンドを実行します。

[root@localhost FlameGraph]# perf record -F 99 -p 17509 -g -- sleep 60
## 60秒経過すると以下の通り出力されます。
[ perf record: Woken up 6 times to write data ]
[ perf record: Captured and wrote 1.985 MB perf.data (2705 samples) ]
## perf.dataができていることの確認
[root@localhost FlameGraph]# ll | grep  perf.data
-rw-------. 1 root root 2092048  9月 28 15:18 perf.data

perf recordのオプションはざっくり以下の意味となります。
-F 99:実行されている命令を99Hzの周期で取得します。
-p 17509:計測対象のPIDを指定します。
-g:コールグラフを有効にします。命令の呼び出し順もとってくるものです。
— sleep 60:60秒のスリープを実行します。

その後、取得したFlameGraphで実行結果を作成します。

[root@localhost FlameGraph]# perf script | ./stackcollapse-perf.pl > out.perf-folded
[root@localhost FlameGraph]# ./flamegraph.pl out.perf-folded > perf-kernel.svg

出来上がったSVGファイルをブラウザで開いてみましょう。

各セクションをクリックすると、そこから上部のスタック部分を詳細に確認することができます。
グラフを簡単に説明すると、真ん中部分が主にリクエストを処理している部分です。インタプリタが多くでてきているあたり、チューニングがまだまだ足りないみたいですね。
右端では、G1GCのコンパイラが動いている様子が示されています。
リクエスト処理をしながらコンパイラが仕事しているものですね。

上部を見ると、javaからkernelへ命令が遷移している様子が見えますね。

データ送信にかかわる箇所では以下のように、Javaのユーザー空間からkernel空間での実行の順番が見えます。

こちらを見ながらカーネル周りの処理内容を見ていくことによってチューニングを実施していくことになります。


これでLinux Kernelの世界に入門できるのではないでしょうか。
Linux Kernelに入門したければJavaを使わず直接C言語でごちゃごちゃやっちゃう手もあるんですけどね。

次回の技術記事はスクレイピングとかfirebaseについて書いてみましょうかね。

CentOS7とJavaの性能検証用環境の構築

  1. その1:概要編
  2. その2:CentOS構築編
  3. その3:Glassfish構築編
  4. その4:Java Servlet構築編
  5. その5:Jmeter設定編
  6. その6:性能計測編 (★★★この記事★★★)
ABOUT ME
kash
エンジニア歴5年目くらい。金融系の業務システムの構築を担っているが、内心はtoC系のシステム構築にかかわるビジネスに携わってみたいと思っている。自分で何かしらのサービスを作ってみよう活動を実施中。バイクが好き。