2016年4月7日

ブロードバンドタワー國武です。

負荷試験を行うには色々なツールがあります。

  • apache bench
  • JMeter
  • httperf
  • etc…

あるシステムの負荷試験に Erlang で実装されたマルチプロトコル対応の tsung というツールを使ってみたので、そのご紹介です。

  1. tsungとは
  2. 検証環境について
  3. インストール方法
  4. 設定方法
    1. クライアント設定
    2. サーバ設定
    3. モニター設定
    4. 負荷設定
    5. セッションの設定
  5. 実行する

tsungとは

tsung (以前は IDX-Tsunamiという名前でした)は様々なプロトコルに対応した erlang で書かれた負荷テストツールです。ライセンスはGNU GPL v2.0 として公開されています。1台、または複数台から、大量のユーザからのアクセスを模擬して負荷を掛けることができます。また、tsung はテスト結果をグラフとしてプロットすることも可能です。最新版の tsung では

  • http/https
  • WebDAV
  • SOAP
  • PostgreSQL
  • MySQL
  • LDAP
  • Jabber/XMPP
  • BOSH
  • MQTT (MQTT v3.1)
  • AMQP

などに対応していますが、ここでは http/https での測定を例に挙げます。

検証構成について

今回は

  • myserver
    • テスト対象のウェブサーバ
  • tsung1
    • 負荷テストツールの tsung のマスターサーバ兼スレーブサーバ
  • tsung2
    • 負荷テストツールのスレーブサーバ

として説明していきます。この記事では、tsung コマンドを実行するサーバをマスターサーバ、実際に負荷を掛けるテスターをスレーブサーバと呼ぶことにします。

インストール方法

実際にCentOS7 に tsung を導入してみます。tsung は、EPELリポジトリにパッケージがあります。tsung1, tsung2 それぞれにインストールしましょう。

$ sudo yum -y install epel-release
$ sudo yum -y install tsung

また、グラフ化するために gnuplot や Perl の Template Toolkit を利用するので、それもインストールしておきます。

$ sudo yum -y install gnuplot perl-Template-Toolkit

設定方法

tsung の設定ファイルは XML で記述されます。tsung をインストールすると設定ファイルのサンプルが

  • /usr/share/doc/tsung-1.5.1/examples

にインストールされるので、これを少しづつ書き換えながら使うのが一番簡単だと思います。今回は

  • http_simple.xml

をベースに説明していきますが、tsung のマニュアルは非常に良く出来ていていますので、英語に抵抗のない方は、そちらを参照されたほうが間違いがないので、お勧めです。

Tsung Documentation (PDF)

まず手始めに自身のホームディレクトリに設定ファイルをコピーしておきます。

$ cp /usr/share/doc/tsung-1.5.1/examples/http_simple.xml ~/

http_simple.xml の初期内容は下記の通りです。

<?xml version="1.0"?>
<!DOCTYPE tsung SYSTEM "@prefix@/share/@PACKAGE_NAME@/@DTD@">
<tsung loglevel="notice" version="1.0">

  <!-- Client side setup -->
  <clients>
    <client host="localhost" use_controller_vm="true"/>
  </clients>
  
  <!-- Server side setup -->
<servers>
  <server host="myserver" port="80" type="tcp"></server>
</servers>

  <!-- to start os monitoring (cpu, network, memory). Use an erlang
  agent on the remote machine or SNMP. erlang is the default --> 
  <monitoring>
    <monitor host="myserver" type="snmp"></monitor>
  </monitoring>
  
  <load>
  <!-- several arrival phases can be set: for each phase, you can set
  the mean inter-arrival time between new clients and the phase
  duration -->
   <arrivalphase phase="1" duration="10" unit="minute">
     <users interarrival="2" unit="second"></users>
   </arrivalphase>
  </load>

  <options>
   <option type="ts_http" name="user_agent">
    <user_agent probability="80">Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Galeon/1.3.21</user_agent>
    <user_agent probability="20">Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.8) Gecko/20050511 Firefox/1.0.4</user_agent>
   </option>
  </options>

  <!-- start a session for a http user. the probability is the
  frequency of this type os session. The sum of all session's
  probabilities must be 100 -->

 <sessions>
  <session name="http-example" probability="100" type="ts_http">

    <!-- full url with server name, this overrides the "server" config value -->

    <request> <http url="/" method="GET" version="1.1"></http> </request>
    <request> <http url="/images/accueil1.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/images/accueil2.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/images/accueil3.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>

    <thinktime value="20" random="true"></thinktime>
    
    <request> <http url="/index.en.html" method="GET" version="1.1" ></http> </request>

  </session>
 </sessions>
</tsung>

これを検証構成に合わせて書き換えていきます。なお、設定ファイル内ではホスト名で記載していますので、myserver, tsung1, tsung2 と、それぞれのIPアドレスを、事前に tsung1, tsung2 の /etc/hosts に書いておく必要があります。

tsung は ssh でスレーブサーバにログインして負荷テストを実行しているので、tsungのマスターサーバから各スレーブサーバに ssh でパスワード認証なしでログインできる必要があります。パスフレーズなしで ssh の鍵を作成してください(どうしてもパスフレーズなしでの運用が難しい場合には ssh-agent を利用しましょう)その後 tsung1 上で

$ ssh-copy-id tsung1
$ ssh-copy-id tsung2

を実行し、tsung1 から各サーバに ssh でログインできることを確認しておきます。

クライアント設定

まずはクライアント設定です。

 <!-- Client side setup -->
  <clients>
    <client host="localhost" use_controller_vm="true"/>
  </clients>

ここでは、tsung1, tsung2 の2台で負荷をかける想定です。

  <clients>
    <client host="tsung1" maxusers='30000'/>
    <client host="tsung2" maxusers='30000'/>
  </clients>

また、maxusers は、通常1プロセスあたりに開けるソケット数に制限があるため、これをバイパスするために利用される設定項目です(ユーザ数がmaxusersに達すると、use_controller_vm が true でない限り、新しい Erlang beam が立ち上がることで、この制限を回避します)。default値は800になっています。1プロセスあたりに開くことのできるファイル数(open files)は ulimit -n で確認できます。

$ ulimit -n
1024

制限を受けないようにするためには、maxusers の値はこの値よりも小さい値である必要があります。maxusers の値を大きくする場合には、事前に open files の値と TCP のチューニングを行っておきます。

  • /etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 1024 65000
fs.file-max = 65000

内容を反映させるために、

$ sudo sysctl -p

を実行しておきましょう。

  • /etc/security/limits.conf
*	soft	nofile	65000
*	hard	nofile	65000

limits.conf は、pam_limits から呼び出されているので、反映させるにはログインし直します。

サーバ設定

<servers>
  <server host="myserver" port="80" type="tcp"></server>
</servers>

ここで myserver とあるのは、負荷を掛ける対象となるWebサーバ名です。ここでは http でのアクセス例ですが、https の場合には

<servers>
  <server host="myserver" port="443" type="ssl"></server>
</servers>

とします。また、”servers” とあるように、複数台を対象とすることも可能ですが、ここでは単体でのテストとします。

モニター設定

  <monitoring>
    <monitor host="myserver" type="snmp"></monitor>
  </monitoring>

モニター設定を入れることで、CPUやload avg、メモリ使用量などを測定できるとありますが、今回は削除しておきます。

負荷設定

次にどんな負荷を掛けるかを記述していきます。

  <load>
  <!-- several arrival phases can be set: for each phase, you can set
  the mean inter-arrival time between new clients and the phase
  duration -->
   <arrivalphase phase="1" duration="10" unit="minute">
     <users interarrival="2" unit="second"></users>
   </arrivalphase>
  </load>

  <options>
   <option type="ts_http" name="user_agent">
    <user_agent probability="80">Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Galeon/1.3.21</user_agent>
    <user_agent probability="20">Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.8) Gecko/20050511 Firefox/1.0.4</user_agent>
   </option>
  </options>

複数のフェーズを設けて、最初は負荷を低めでアクセスさせるといったこともできます。ここでは duration で指定された時間(分)の間、interarrival 秒ごとに、新規にセッションをサーバに張りに行きます。このセッションがすべて処理された段階でテストは終了することになります。ここでは少し複雑な場合を模擬します。

  <load>
   <arrivalphase phase="1" duration="3" unit="minute">
     <users maxnumber="100" interarrival="1" unit="second"></users>
   </arrivalphase>
   <arrivalphase phase="2" duration="3" unit="minute">
     <users maxnumber="200" interarrival="0.1" unit="second"></users>
   </arrivalphase>
  </load>

上記設定とすることで、最初の3分間は 1秒間に1ユーザづつ新規にアクセスしてきます。ただし、100ユーザに達したら打ち止めです。次のフェーズでは 1秒間に10ユーザづつ新規にアクセスしてきます。こちらは 200ユーザに達したら打ち止めです。
後述するセッションで、1ユーザがリクエストするファイルが9ファイルだとすると、単純計算でも

10 ✕ 9 = 90 request/sec

の負荷を捌けないと遅延していくことがわかります。なお、<option> で指定されているのは、ユーザクライアントの情報です。probability の値により、どれぐらいの割合でその情報が使われるかが決まります。そのため probability の値は、すべて足して 100になる必要があります。

セッションの設定

次に、1ユーザが生成するアクセス内容を記述します。

 <sessions>
  <session name="http-example" probability="100" type="ts_http">

    <request> <http url="/" method="GET" version="1.1"></http> </request>
    <request> <http url="/images/accueil1.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/images/accueil2.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/images/accueil3.gif" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>

    <thinktime value="20" random="true"></thinktime>
    
    <request> <http url="/index.en.html" method="GET" version="1.1" ></http> </request>

  </session>
 </sessions>

<sessions> とあるように、複数の <session> を定義することも可能です。また、最新版では Basic認証だけでなくDigest認証、OAuth 1.0 での認証も可能になったそうですが、ここでは触れません。

ページ遷移を模すために、<thinktime></thinktime> で待ち時間を挿入することもできます。単位は秒数です。randome=”true”とすると、value を平均値とする指数分布となる待ち時間が挿入されます。

今回は、単純に複数の画像ファイルが貼られているページを1枚閲覧するケースを試しましょう。

 <sessions>
  <session name="http-example" probability="100" type="ts_http">

    <request> <http url="/" method="GET" version="1.1"></http> </request>
    <request> <http url="/01.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/02.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/03.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/04.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/05.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/06.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/07.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>
    <request> <http url="/08.jpg" method="GET" version="1.1" if_modified_since="Fri, 14 Nov 2003 02:43:31 GMT"></http> </request>

  </session>
 </sessions>

いちいち手で書くのは面倒だと思いますが、tsung-recorder を使うと、プロキシサーバとなって、ページ遷移を記録してくれたりもします。

$ tsung-recorder start
Starting Tsung recorder on port 8090
"Record file: /home/vagrant/.tsung/tsung_recorder20160307-0053.xml"

default では 8090 番ポートを Listen するので、ブラウザにプロキシの設定をしましょう。記録を終えるには

$ tsung-recorder stop
[OK]

とします。生成されたファイル(この例では ~/.tsung/tsung_recorder20160307-0053.xml) を眺めてみると

<session name='rec20160307-0055' probability='100'  type='ts_http'>
<request><http url='http://192.0.2.41/' version='1.1' method='GET'></http></request>
<request><http url='/' version='1.1' method='GET'></http></request>

<thinktime random='true' value='5'/>

<request><http url='/' version='1.1' method='GET'></http></request>

<thinktime random='true' value='7'/>

<request><http url='http://192.0.2.40/' version='1.1' method='GET'></http></request>
<request><http url='/01.jpg' version='1.1' method='GET'></http></request>
<request><http url='/02.jpg' version='1.1' method='GET'></http></request>
<request><http url='/03.jpg' version='1.1' method='GET'></http></request>
<request><http url='/04.jpg' version='1.1' method='GET'></http></request>
<request><http url='/05.jpg' version='1.1' method='GET'></http></request>
<request><http url='/06.jpg' version='1.1' method='GET'></http></request>
<request><http url='/07.jpg' version='1.1' method='GET'></http></request>
<request><http url='/07.jpg' version='1.1' method='GET'></http></request>
</session>

このように 〜 が生成されるので、利用する際には、設定ファイル内をこれで置き換えます。<http url=に、ブラウザでアクセスした際のホスト名が入るので、別途環境に合わせて修正する必要があることや、不要な<thinktime>の削除、意図せず外部サービスに負荷を掛けてしまわまいように、外部サービスを埋め込んでいる箇所(Facebookのいいねボタンや Google Analyticsのトラッキングコード)へのアクセスを削除するなど、微調整は別途必要になります。

上記の例では、最初誤って別サーバ(192.0.2.41)にアクセスした記録が残っているので、これも削除対象ですね。

実行する

実行ログを保存するためのディレクトリを作成しておきます。

$ sudo mkdir logs

あとは

$ tsung -l logs -f http_simple.xml start
Starting Tsung
"Log directory is: /home/vagrant/log/20160308-0730"

で実行されます。実行結果をグラフ化するには tsung_stats コマンドを実行します。html 形式でレポートが出力されます。実行したディレクトリにレポートファイルが出力されるので、適当なディレクトリを作成しておきましょう。

$ mkdir report && cd report
$ tsung_stats --stats ../logs/20160308-0730/tsung.log

report.html を開くと

stats-report

このように、テスト結果が表示されます。左ペインの Graphs Report をクリックするか、graph.html を直接開くと

graphs-report

のように、結果がグラフとして表示されます。tsung の設定ファイルはちょこちょこと書き換えて複数回テストすることになるかと思いますが、logs ディレクトリにその設定ファイルが保存されるので、どういった条件でテストしたかは、保存された設定ファイルを参照することでも確認可能です。

以上、簡単ですが tsung のご紹介でした。tsung では、簡単に高負荷を掛けられるので、一度検証などでお試しください。

本ブログの情報につきましては、自社の検証に基づいた結果からの情報提供であり、
品質保証を目的としたものではございません。

アバター

投稿者: Koichi KUNITAKE

最近は Ansible やら Sphinx 触ってます。IPv6 はボチボチ……