JMeter を復習し始めているかっぱです。

tl;dr

JMeter が標準で出力する CSV ログを Embulk と Elasticsearch + Kibana で可視化してみようという考察です。

参考

考察

モチベーション

  • JMeter の結果の見方をちゃんと理解したい
  • 結果から何が読み取れるかを把握したい
  • Backend Lister を利用して InfluxDB + Grafana で可視化することも出来るけど負荷が高く、本来の負荷試験に影響が出た思い出がある

環境

以下のバージョンを利用。

% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.11.4
BuildVersion:   15E65

% vagrant version
Installed Version: 1.8.1
Latest Version: 1.8.1

$ ./apache-jmeter-2.13/bin/jmeter --version
Copyright (c) 1998-2015 The Apache Software Foundation
Version 2.13 r1665067

構成はざっくり以下のようなイメージ。

20160511143157

環境の構築

以下のように Vagrant を利用して JMeter を実行する環境を起動する。

#
Vagrant.configure(2) do |config|
  config.vm.box = "dummy"
  config.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"

  config.vm.provider :aws do |aws, override|
    # aws.aws_dir = ENV['HOME'] + "/.aws/"
    # aws.aws_profile = "default"
    aws.access_key_id = ENV["AWS_ACCEESS_KEY_ID"]
    aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
    aws.region = "ap-northeast-1"
    aws.keypair_name = "key-name"
    aws.ami = "ami-29160d47"
    override.ssh.username = "ec2-user"
    override.ssh.private_key_path = ENV["HOME"] + "/.path/to/key.pem"
    aws.security_groups = ["sg-xxxxxx0", "sg-xxxxxx1"]
    aws.subnet_id = "subnet-xxxxxxxxx"
    aws.instance_type = "t2.micro"
    aws.tags = {
      'Name' => 'Vagrant_EC2-01'
    }
  end

  config.vm.provision :shell, :path => "bootstrap.sh"
  config.vm.synced_folder "./jmx/", "/vagrant/jmx/", type: "rsync"
  config.vm.synced_folder "./result/", "/vagrant/result/", type: "rsync_pull"
end

事前に vagrant-aws と vagrant-rsync-pull をインストールしておく。

% vagrant plugin install vagrant-aws
% vagrant plugin install vagrant-rsync-pull

シナリオ作りは ruby-jmeter

シナリオは ruby-jmeter を利用して Ruby DSL で記載する。

% cat plan.rb
require 'rubygems'
require 'ruby-jmeter'

test do
  threads count: 10 do
    visit name: 'kome.inokara.com', url: 'http://kome.inokara.com'
  end
end.jmx(file: "./jmx/plan.jmx")

以下のようにシナリオを生成する。

% bundle exec ruby plan.rb

シナリオはカレントディレクトリの jmx ディレクトリ以下に保存される。

% ls -l ./jmx
total 8
-rw-r--r--  1 username  staff  3327 May 10 16:43 plan.jmx

シナリオの転送は vagrant sync を利用することでちょっと手軽に…

% vagrant rsync
==> default: Rsyncing folder: /Users/username/path/to/vagrant-ec2-jmeter/jmx/ => /vagrant/jmx
==> default: Rsyncing folder: /Users/username/path/to/vagrant-ec2-jmeter/ => /vagrant

JMeter を実行する

起動したインスタンスにログインして JMeter を実行する。

% vagrant ssh

JMeter を実行する前に結果の CSV ファイルを少しだけカスタマイズしたいので ${JMETER_HOME}/bin/user.properties に以下を追記する。

jmeter.save.saveservice.output_format=csv
jmeter.save.saveservice.data_type=false
jmeter.save.saveservice.label=true
jmeter.save.saveservice.response_code=true
jmeter.save.saveservice.response_data.on_error=false
jmeter.save.saveservice.response_message=false
jmeter.save.saveservice.successful=true
jmeter.save.saveservice.thread_name=true
jmeter.save.saveservice.time=true
jmeter.save.saveservice.subresults=false
jmeter.save.saveservice.assertions=false
jmeter.save.saveservice.latency=true
jmeter.save.saveservice.bytes=true
jmeter.save.saveservice.hostname=true
jmeter.save.saveservice.thread_counts=true
jmeter.save.saveservice.sample_count=true
jmeter.save.saveservice.response_message=false
jmeter.save.saveservice.assertion_results_failure_message=false
jmeter.save.saveservice.timestamp_format=yyyy-MM-dd'T'HH:mm:ss.SSSZ
jmeter.save.saveservice.default_delimiter=,
jmeter.save.saveservice.print_field_names=true

CSV のヘッダを出力する、タイムスタンプのフォーマットを変更する等のカスタマイズを加えている。

以下のように JMeter を起動して負荷を掛ける。

$ ${JMETER_HOME}/bin/jmeter --nongui --testfile /vagrant/jmx/plan.jmx --logfile /vagrant/result/result.csv

結果の収集

JMeter の結果をローカルにダウンロードしてくる必要があるが、これも vagrant コマンドで少し手軽に。

% vagrant rsync-pull
==> default: Rsyncing folder: /Users/username/path/to/vagrant-ec2-jmeter/result/ => /vagrant/result/
==> default:   - Exclude: [".vagrant/", "Vagrantfile"]

% ls -l ./result/
total 5672
-rw-rw-r--  1 username  staff  2904000 May 10 18:09 result.csv

中身は以下のような CSV ファイルになっている。

timeStamp,elapsed,label,responseCode,threadName,success,bytes,grpThreads,allThreads,Latency,SampleCount,ErrorCount,Hostname
2016-05-10T09:08:18.858+0000,233,kome.inokara.com,200,ThreadGroup 1-1,true,4307,1,1,233,1,0,ip-xxx-xx-xx-xxx
2016-05-10T09:08:19.092+0000,27,kome.inokara.com,200,ThreadGroup 1-1,true,4307,2,2,27,1,0,ip-xxx-xx-xx-xxx
2016-05-10T09:08:19.120+0000,32,kome.inokara.com,200,ThreadGroup 1-1,true,4307,2,2,32,1,0,ip-xxx-xx-xx-xxx
2016-05-10T09:08:19.102+0000,57,kome.inokara.com,200,ThreadGroup 1-2,true,4307,2,2,57,1,0,ip-xxx-xx-xx-xxx

各ヘッダについてはこちらこちらより抜粋。

csv ヘッダ 詳細
timeStamp 開始時刻
elapsed リクエストを送出してからレスポンスが終了するまでの経過時間(ms)
responseCode HTTPレスポンスコード
threadName JMeter スレッド名
success リクエストに対して結果が返ってきたかどうか
bytes 送受信バイト数
grpThreads そのスレッドグループ内でアクティブなスレッド数
allThreads 全てのスレッドグループのトータルアクティブスレッド数
Latency リクエストを送出してから最初の 1 バイトが帰ってくるまでの経過時間(ms)
SampleCount サンプル数
ErrorCount エラー数
Hostname サンプルが生成されたホスト

embulk で Elasticsearch に結果を放り込む

embulk のインストール方法等は割愛。また、 embulk-output-elasticsearch プラグインは導入済み、Elasticsearch + Kibana は起動済みという前提で…以下のような設定ファイルを作成する。

in:
  type: file
  path_prefix: "./result/result.csv"
  parser:
    type: csv
    charset: UTF-8
    newline: CRLF
    delimiter: ","
    quote: '"'
    escape: '"'
    null_string: 'NULL'
    skip_header_lines: 1
    comment_line_marker: '#'
    columns:
    - {name: timeStamp, type: timestamp, format: '%Y-%m-%dT%H:%M:%S'}
    - {name: elapsed, type: long}
    - {name: label, type: string}
    - {name: responseCode, type: string}
    - {name: threadName, type: string}
    - {name: success, type: boolean}
    - {name: bytes, type: long}
    - {name: grpThreads, type: long}
    - {name: allThreads, type: long}
    - {name: Latency, type: long}
    - {name: SampleCount, type: long}
    - {name: ErrorCount, type: long}
    - {name: Hostname, type: string}

out:
  type: elasticsearch
  index: jmeter
  index_type: result
  nodes:
    - host: ${elasticsearch-host}

ファイル名は config.yml で保存して preview で確認

% embulk preview config.yml -b bundle

以下のように出力される。

2016-05-10 23:34:07.390 +0900: Embulk v0.8.8
2016-05-10 23:34:08.271 +0900 [INFO] (0001:preview): Listing local files at directory 'result' filtering filename by prefix 'result.csv'
2016-05-10 23:34:08.276 +0900 [INFO] (0001:preview): Loading files [result/result.csv]
-
|timeStamp:timestamp|elapsed:long   |label:string|responseCode:string|threadName:string|success:boolean | bytes:long
|grpThreads:long    |allThreads:long|Latency:long|SampleCount:long   |ErrorCount:long  |Hostname:string|
-

(snip)

|2016-05-10 09:08:21 UTC|40|kome.inokara.com|200|ThreadGroup1-6|rue |4,307|6|6|40|1|0|ip-xxx-xx-x-xxx|
|2016-05-10 09:08:21 UTC|30|kome.inokara.com|200|ThreadGroup1-3|true|4,307|6|6|30|1|0|ip-xxx-xx-x-xxx|
-

あとはよしなに可視化

20160510233956

Visualize の設定を書き込んでみた。

20160511085811

以上

JMeter の結果は csv で

なんとかなるので無理して Backend Listener とかを利用する必要は無い気がする。

embulk アリガタヤ

カラムの定義は必要になるが、それさえ頑張れば簡単に Elasticsearch に放り込めるのは素晴らしい!

Kibana をちゃんと使えれば

それなりの分析基盤になると思う(今回の考察はあくまでも「使ってみたレベル」)

ということで…

考察でした。

appendix

embulk のインストール

% curl --create-dirs -o ~/.embulk/bin/embulk -L "http://dl.embulk.org/embulk-latest.jar"
% chmod +x ~/.embulk/bin/embulk
% echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.zshrc
% source ~/.zshrc

embulk のプラグインインストール

% embulk mkbundle bundle
% vim bundle/Gemfile

gem 'embulk-output-elasticsearch'

% cd bundle
% embulk bundle

Elasticsearch + Kibana を立ち上げる docker-compose.yml

elasticsearch:
  image: elasticsearch
  ports:
    - 9200:9200
    - 9300:9300

kibana:
  image: kibana
  ports:
    - 5601:5601
  links:
    - elasticsearch

以下のように起動する。

% docker-compose up -d

元記事はこちら

JMeter の CSV 結果を eEK Stack(embulk + Elasticserach + Kibana) で可視化する考察