私はパフォーマンスチューニングが得意なこともあり、負荷試験を行う場面がそこそこあります。負荷試験ツールにはいろいろなものがありますが、古くからあり情報も多いJMeterを使うケースは今でもそれなりに多いと思います。JMeterはGUIで設定ができて手軽なのですが、複雑なシナリオをGUIでポチポチ作るのは面倒です。シナリオをXML形式で出力することもできますが、XMLは読み書きしづらいですし、JMeterのGUIでシナリオを実行してはいけないとのことです。それなら最初からわざわざGUIを起動したくないですよね。
そこで、RubyのDSLでJMeterのシナリオを記述できる__ruby-jmeter__を使って、Ralisアプリの負荷試験を継続的に行う環境を作っていきます。
JMeterをインストール
公式サイトでダウンロードできます。今回は、2021/03/15現在の最新バージョンである5.4.1を使用します。Macを使っている方はHomebrewでインストールできます。
$ brew install jmeter
JMeterを動かすにはJavaが必要ですが、詳しくはJMeterを起動する際の指示に従ってください…。
負荷試験対象のRailsアプリを用意
普段開発しているRailsアプリで行ってもらって構いません。本記事では、サンプルとしてRailsチュートリアルで作成するアプリを拝借し、Rails 6.0.xのアプリをRuby 2.7.xで動かします。
$ git clone https://github.com/yasslab/sample_apps.git
$ cd sample_apps/6_0_0/ch14
$ bundle install --without production
$ yarn install
$ bin/rails db:setup # シードデータも投入されます
$ bin/rails s
IDが1のユーザにはマイクロポストが50件登録されていますが、IDが50のユーザには1件も登録されていません。これらのユーザ詳細ページに対して負荷試験を行い、どのくらい差が出るか検証してみます。
ruby-jmeterをインストール
Gemfileにruby-jmeterを追記し、インストールします。
gem 'ruby-jmeter'
$ bundle install
負荷試験のシナリオを実行するRakeタスク
試しに、同時接続数が10、測定時間が60秒のシナリオを定義して実行してみます。ruby-jmeterだけでJMeterを実行することもできますが、ソースを見る限りHTML形式のレポートを出力できないので、ruby-jmeterではjmxファイルの生成のみ行い、JMeterの実行は直接コマンドを叩くことにします。
namespace :jmeter do
desc "Run JMeter"
task run: :environment do
test do
threads count: 10, duration: 60 do
visit name: 'User 01', url: 'http://localhost:3000/users/1'
visit name: 'User 50', url: 'http://localhost:3000/users/50'
end
end.jmx(file: 'jmeter.jmx')
system('jmeter -n -t jmeter.jmx -l jmeter.jtl -e -o report -f')
end
end
$ bin/rails jmeter:run
実行が終わると、カレントディレクトリにHTML形式のレポートが出力されているので、 ./report/index.html
をブラウザで開いてみましょう。私の環境で実行したところ、以下のような結果になりました。developmentで動かしていることもあり、レイテンシーに結構差が出ていますね🚀
最後に
コマンド一発で負荷試験できるようになれば、あとはCIに組み込んで自動実行させるだけです。負荷試験は本番環境に近い環境で実行しないと良い効果を得られないので、実際に稼働している本番環境に対して行うか、それに近い専用の環境を用意して行うようにしましょう。
なお、JMeterのコマンドラインオプションについては --?
オプションで確認できる(珍しいオプションですね👀)ので、興味があれば見てみてください。