2013年12月3日

Apache JMeterでPostgreSQLの負荷試験をする

このエントリは、PostgreSQL Advent Calendar 2013のDay3の記事です。

「データベースの負荷試験」を考える時、皆さんはどのような方法で実施することを検討するでしょうか。自前のテストスクリプトでしょうか。あるいは、データベース単体の負荷試験は行わず、Webシステム全体の負荷試験として実施するでしょうか。

PostgreSQLには、pgbenchというベンチマークツールが付属しており、このツールのシナリオを作成することで多少は独自のシナリオでの試験を行うことも可能ですが、状況によってはそれだけでは自由度が不足することがあります。

今回は、Webシステムの負荷テストでよく使われるJMeterを使って、自由なシナリオでPostgreSQL単体の負荷試験を行う方法を紹介します。

(なお、JMeterは非常に多機能な負荷生成ツールですので、今回はJMeterの網羅的な説明ではなく、あくまでもPostgreSQLのテストをする際の観点に絞って紹介します。JMeterの詳細については、他の情報を参考にしてください)

■事前準備

事前準備として、以下のインストール、設定を行う必要があります。
  • Java SE
  • Apache JMeter
  • PostgreSQL JDBCドライバ
  • PostgreSQL
今回は、Java SEとPostgreSQLそのもののインストールについては割愛します。

まず、Apache JMeterを入手します。
本記事執筆時点での最新版は2.10で、Java SE 6以降を必要とします。apache-jmeter-2.10.zipをダウンロードして、適当なディレクトリに展開しておきます。

次にPostgreSQLのJDBCドライバを入手します。

PostgreSQLのJDBCドライバは、JavaSEの1.5以降を必要とします。また、PostgreSQLのJDBCドライバにはJDBC3とJDBC4、JDBC41の3種類あり、Java SEのバージョンによって対応するドライバのバージョンが異なってきます。

Java 1.5を使っている場合にはJDBC3、Java SE 6を使っている場合にはJDBC4、Java SE 7または8を使っている場合にはJDBC41を使います。(Apache JMeterはJava SE 6以降を必要としますので、JDBCドライバもJDBC4以降を使うことになるでしょう)

詳細は、PostgreSQLのJDBCドライバのダウンロードページをご覧ください。
JDBCドライバをダウンロードしたら、JMeterのディレクトリの中にある lib\ext ディレクトリ内に配置します。


JMeterの bin ディレクトリ内にあるjmeter.bat(Linux/Unixの場合はjmeterを実行してJMeterが起動したら、インストールは完了です。


■JDBC接続の設定

まず、テストの大枠となる「スレッドグループ」を作成します。「テスト計画」で右クリックし、「追加→Threads(Users)→スレッドグループ」で追加します。

次に、スレッドグループ内で使用するJDBC接続を設定します。作成したスレッドグループで右クリックし、「追加→設定エレメント→JDBC Connection Configuration」で設定項目を追加します。

JDBC Connection Configurationの設定画面では、最低限、以下の項目を設定する必要があります。
  • Variable Name Bound to Pool
    • Variable Name
  • Database Connection Configuration
    • Database URL
    • JDBC Driver Class
    • Username
    • Password
「Variable Name Bound to Pool」は、この後にJDBCリクエスト(SQL文)を設定する際、この接続と紐付けるための文字列です。ここでは「pgsql」を設定します。

「Database Connection Configuration」は、文字通り、データベースへの接続の設定です。通常のJDBCドライバで接続する際の設定項目と同等の内容です。ここでは、同じマシンのtestdbデータベースに接続するため、
  • Database URL: jdbc:postgresql://localhost:5432/testdb
  • JDBC Driver class: org.postgresql.Driver
  • Username: postgres
  • Password: postgres
という設定を行います。


■JDBCリクエストの設定

次に、現在作成したJDBC Conection Configurationを使ったJDBCリクエストを設定してみます。ここでは、まず第一歩として select version() を実行してみます。

スレッドグループで右クリックし、「追加→サンプラー→JDBC Request」としてJDBC Requestを追加します。

作成したJDBC Requestの設定項目の中から、「Variable Name Bound to Pool」には先ほどJDBC Connection Configurationで設定した「pgsql」を指定します。

SQL Queryには「select version();」を設定します。


■実行結果の表示と統計レポート

最後に、実行結果を確認するためのエレメントを追加します。スレッドグループで右クリックし、「追加→リスナー→結果をツリーで表示」とします。

また、同様に「追加→リスナー→統計レポート」として統計レポートも追加しておきます。


ここまでできたら、一旦、テスト計画(jmxファイル)を保存します。CTRL-Sでディレクトリやファイル名を指定して保存します。

■テスト計画の実行

テスト計画を保存したら、このテスト計画を実行してみます。ツールバーの中ほどにある「実行」ボタンをクリックします。

■実行結果の確認

実行終了すると、「結果をツリーで表示」の中に「JDBC Request」が現れます。

「応答データ」のタブを表示すると、先ほど設定した「select version();」の応答となる文字列が返却されていることが分かります。


また、「統計レポート」を見ると、JDBC Requestが一回実行されて、エラーは発生しなかったことも分かります。

■JDBC Requestで取得した値を次のJDBC Requestで使う

ここまでで、データベースへJDBCリクエストを発行してその結果を確認することができるようになりましたが、実際のデータベースの負荷試験のシナリオはもっと複雑になるのが普通です。

特に、最初に取得した値を次のSQLのパラメータに与えて実行したい、というケースは多いと思います。

ここでは、最初のJDBC Requestで現在の時刻を取得し、その値を次のJDBC RequestでテーブルにINSERTする、というシナリオを考えてみます。ロジックとしては、
SELECT now() INTO :ts;
INSERT INTO t1 VALUES ( :ts );
のような内容になります。

まず、最初のJDBC Requestを「JDBC Request 1」として作成し、SQL Queryに
SELECT now();
を設定します。 この時、設定の下の方にある「Variable names」に「rs」と設定します。この設定を行うことによって、このクエリで取得した結果を、次のクエリで使用できるようになります。(JMeter変数への保存)


次に、「JDBC Request 2」を追加して、SQL Queryに
insert into t1 values ( '${rs_1}' );
を指定します。また、Query Typeとして「Update Statement」を選択します。


最後に、スレッドグループで右クリックし、「追加→サンプラー→Debug Sampler」としてDebug Samplerを追加します。

このDebug Samplerを使うことによって、JDBC Requestの中でやり取りされる変数名やその中身を「結果をツリーで表示」の中で確認することができます。

■シナリオの実行と実行結果の確認

それでは、t1テーブルを作成して、このシナリオを実行してみます。
create table t1 (
  ts timestamp
);
を実行して、t1テーブルを作成します。

テーブルを作成したら、テスト計画を実行します。

実行後、t1テーブルにタイムスタンプが記録されていたら成功です。何度か繰り返して、異なる値が記録されることを確認します。


この時、「結果をツリーで表示」を見ると「Debug Sampler」のサンプル結果が記録されており、「応答データ」のタブを見ると、「rs_#」と「rs_1」が表示されていることが分かります。


これは、先ほど「JDBC Request 1」で「Variable names」に設定した「rs」の中身になります。

このように、Debug Samplerを設定することによってJMeterとPostgreSQLとの間のやり取りを確認することができますので、この中身を確認しながらテストのシーケンスをJMeterのシナリオとして実装していきます。

■まとめ

今回紹介した以外にも、JMeterでは「設定エレメント」の「Random Variable」を使うと乱数を取得できたり、タイマを使うとテストシナリオの中でウェイトを入れたりと、さまざまなテストシナリオを実装することができます。当然ながら、多重度などを設定して負荷を調整することもできます。

Webサーバやアプリケーションサーバと違い、データベースサーバは簡単に増やしたりすることができないため、パフォーマンスのボトルネックになりやすく、きちんとしたデータベースの負荷試験を実施しておくことは、その後の運用も見据えると非常に重要なことです。

ぜひ、JMeterをうまく使いこなして、適切な負荷試験を実施できるようになりましょう。

では、また。

0 件のコメント:

コメントを投稿