ELB+EC2(1台)の構成で、Gatling で負荷テストしてみます。
1.WEBサーバの準備
テスト対象のWEBサーバを用意します。
今回は、AmazonLinux のAMIでEC2を作成し、インスタンスタイプは、t2.nano にしました。
1.1.パッケージのインストール
このEC2インスタンスに Apache、Tomcat をインストールします。また、Tomcatのサンプルアプリケーションもインストールします。
[ec2-user@ip-10-0-11-160 ~]$ sudo yum install httpd tomcat8 tomcat8-webapps
1.2.Apacheの設定
Apache を worker で動かします。
/etc/sysconfig/httpd を修正します。
下記がコメントアウトされているので1桁目の "#" を削除して、有効にします。
HTTPD=/usr/sbin/httpd.worker/etc/httpd/conf/httpd.conf を修正します。
ELB向けに Timeout と Keepalive の設定を変更します。
KeepAliveTimeout は、ELBのアイドルタイムアウトより長くします。
KeepAlive On MaxKeepAliveRequests 50 KeepAliveTimeout 120
MPMは 以下のようにしました。 MaxClient をデフォルトより増やしています。
<IfModule worker.c> StartServers 4 MaxClients 512 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 64 MaxRequestsPerChild 0 </IfModule>
1.3.ApacheとTomcat連携の設定
/etc/httpd/conf.d/proxy_ajp.conf を作成して、内容を以下のようにします。
Tomcat のサンプルアプリけしょんが動くようにします。
<Location /sample/> ProxyPass ajp://localhost:8009/sample/ keepalive=on ProxyPassReverse ajp://localhost:8009/sample/ </Location>
1.4.Tomcat の設定
Tomcat はデフォルト設定で使用します。
1.5.ヘルスチェックページの用意
ELBが使用するヘルスチェック用のページを用意します。
[ec2-user@ip-10-0-11-160 html]$ cat /var/www/html/alive alive
1.6.ApacheとTomcat の起動
サービスを起動します
[ec2-user@ip-10-0-11-160 ~]$ service httpd start [ec2-user@ip-10-0-11-160 ~]$ service tomcat start
1.7.動作確認
curl を使用して、Apache経由でTomcat のサンプルアプリケーションにアクセスします
[ec2-user@ip-10-0-11-160 ~]$ curl http://localhost/sample/hello <html> <head> <title>Sample Application Servlet Page</title> </head> <body bgcolor=white> <table border="0"> <tr> <td> <img src="images/tomcat.gif"> </td> <td> <h1>Sample Application Servlet</h1> This is the output of a servlet that is part of the Hello, World application. </td> </tr> </table> </body> </html>
バージョンは以下のとおり
[ec2-user@ip-10-0-11-160 ~]$ apachectl -V Server version: Apache/2.2.31 (Unix) Server built: Jul 19 2016 00:11:53 Server's Module Magic Number: 20051115:40 Server loaded: APR 1.5.1, APR-Util 1.4.1 Compiled using: APR 1.5.1, APR-Util 1.4.1 Architecture: 64-bit Server MPM: Worker threaded: yes (fixed thread count) forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/worker" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=128 -D HTTPD_ROOT="/etc/httpd" -D SUEXEC_BIN="/usr/sbin/suexec" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf" [ec2-user@ip-10-0-11-160 ~]$ rpm -aq | grep tomcat8 tomcat8-servlet-3.1-api-8.0.35-1.61.amzn1.noarch tomcat8-lib-8.0.35-1.61.amzn1.noarch tomcat8-el-3.0-api-8.0.35-1.61.amzn1.noarch tomcat8-jsp-2.3-api-8.0.35-1.61.amzn1.noarch tomcat8-8.0.35-1.61.amzn1.noarch tomcat8-webapps-8.0.35-1.61.amzn1.noarch
ApacheとTomcatの制限値はデフォルトです。
[ec2-user@ip-10-0-11-160 ~]$ cat /proc/`pgrep java|head -1`/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 1898 1898 processes Max open files 4096 4096 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 1898 1898 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us [ec2-user@ip-10-0-11-160 ~]$ cat /proc/`pgrep httpd|head -1`/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 1898 1898 processes Max open files 1024 4096 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 1898 1898 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us
2.ELBを作成
内部用ELBを作成して、上記で作成してWEBサーバを登録します。
各種パラメータはデフォルト値にします。
ヘルスチェック用のURLは "/alive" にします。
3.Gatling用サーバの準備
Gatlingを動かすサーバを用意します。
今回は、AmazonLinux のAMIでEC2を作成し、インスタンスタイプは、t2.nano にしました。
3.1.Javaのインストール
OpenJDKを使います
[ec2-user@ip-10-0-11-193 ~]$ sudo yum install java-1.8.0-openjdkバージョンを確認します。
[ec2-user@ip-10-0-11-193 ~]$ java -version openjdk version "1.8.0_101" OpenJDK Runtime Environment (build 1.8.0_101-b13) OpenJDK 64-Bit Server VM (build 25.101-b13, mixed mode)
このとき、別のバージョンが表示されるようであれば、以下のようにして切り替えます。
[ec2-user@ip-10-0-11-193 ~]$ sudo alternatives --config java There are 2 programs which provide 'java'. Selection Command ----------------------------------------------- * +1 /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java 2 /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java Enter to keep the current selection[+], or type selection number: 2
3.2.Gatling のインストール
Gatling のサイトから zip ファイルをダウンロードして、workspace ディレクトリで解凍します。
解凍後のディレクトリ名が長すぎるので、短い名称に変更します。
[ec2-user@ip-10-0-11-193 ~]$ mkdir ~/workspace [ec2-user@ip-10-0-11-193 ~]$ cd ~/workspace [ec2-user@ip-10-0-11-193 workspace]$ curl -OL https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/2.2.2/gatling-charts-highcharts-bundle-2.2.2-bundle.zip [ec2-user@ip-10-0-11-193 workspace]$ unzip ./gatling-charts-highcharts-bundle-2.2.2-bundle.zip [ec2-user@ip-10-0-11-193 workspace]$ mv ./gatling-charts-highcharts-bundle-2.2.2-bundle gatling
3.3.Gatlingのテストシナリオ作成
テストシナリオは、以下のようにしたいと思います。
・1ユーザ1アクセスにする
・/sample/hello にアクセスする
・レスポンスのステータスが 200 であることをチェックする
・レスポンスに "Sample Application Servler" が含まれることをチェックする
・2分間の合計で10000ユーザになるまで段階的にユーザを増減させる。
Gatoling のテストケースは、以下のとおり。
後述しますが、Gatling 実行時に メニューの class 名が表示されます。
[ec2-user@ip-10-0-11-193 workspace]$ cat ./gatling/user-files/simulations/test.scala
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class TestMySimulation extends Simulation {
val httpConf = http
.baseURL("http://internal-in-elb-1279773330.us-east-1.elb.amazonaws.com")
.acceptCharsetHeader("ISO-8859-1,utf-8;q=0.7,*;q=0.7")
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3")
.disableFollowRedirect
val scn = scenario("Test Scenario")
.exec(http("request")
.get("/sample/hello")
.check(status.is(200))
.check(regex( """Sample Application Servlet"""))
)
setUp(scn.inject(
//atOnceUsers(1)
//rampUsersPerSec(1).to(60).during(30),
//constantUsersPerSec(60) during(300),
//rampUsersPerSec(60).to(1).during(30)
heavisideUsers(10000) over(120 seconds)
).protocols(httpConf))
}
3.4.Gatling実行時にDNSキャッシュを無効にする
JavaはデフォルトでDNSキャッシュが有効になっています。
ELBはDNSラウンドロビンを使用しているので、アクセスに偏りでできないように、JavaのDNSキャッシュを無効にします。
下記の赤字部分を追加します。
[ec2-user@ip-10-0-11-193 gatling]$ cat ./bin/gatling.sh
~省略~
JAVA_OPTS="${JAVA_OPTS} -XX:+HeapDumpOnOutOfMemoryError"
JAVA_OPTS="${JAVA_OPTS} -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false"
JAVA_OPTS="${JAVA_OPTS} -Dsun.net.inetaddr.ttl=0 -Dsun.net.inetaddr.negative.ttl=0"
COMPILER_OPTS="$JAVA_OPTS -Xss100M"
# Setup classpaths
~省略~
3.5.Gatlingのレポートをブラウザでみれるようにする
このレポートをブラウザで見るために Apache をインストールして、レポートが格納されたディレクトリにリンクを作成します。
apache ユーザで参照できるように、/home/ec2-user のパーミションを変更しています。
[ec2-user@ip-10-0-11-193 ~]$ sudo yum install httpd [ec2-user@ip-10-0-11-193 ~]$ chmod 755 /home/ec2-user [ec2-user@ip-10-0-11-193 workspace]$ ln -s /home/ec2-user/workspace/gatling/results /var/www/html/gatling [ec2-user@ip-10-0-11-193 ~]$ service httpd start
4.Gating の実行
準備ができたので、Gatling を実行します。
以下のようにして、gatling.sh を実行すると、上記で作成したテストシナリオが一覧に表示されるので、番号で選択してシナリオを実行します。
緑字部分で ENTER します。
[ec2-user@ip-10-0-11-193 workspace]$ ./gatling/bin/gatling.sh GATLING_HOME is set to /home/ec2-user/workspace/gatling Choose a simulation number: [0] TestMySimulation [1] computerdatabase.BasicSimulation [2] computerdatabase.advanced.AdvancedSimulationStep01 [3] computerdatabase.advanced.AdvancedSimulationStep02 [4] computerdatabase.advanced.AdvancedSimulationStep03 [5] computerdatabase.advanced.AdvancedSimulationStep04 [6] computerdatabase.advanced.AdvancedSimulationStep05 0 <ENTER> Select simulation id (default is 'testmysimulation'). Accepted characters are a-z, A-Z, 0-9, - and _ <ENTER> Select run description (optional) <ENTER> Simulation TestMySimulation started... ~省略~ ================================================================================ 2016-07-23 05:32:27 117s elapsed ---- Test Scenario ------------------------------------------------------------- [##########################################################################]100% waiting: 0 / active: 0 / done:10000 ---- Requests ------------------------------------------------------------------ > Global (OK=10000 KO=0 ) > request (OK=10000 KO=0 ) ================================================================================ Simulation TestMySimulation completed in 117 seconds Parsing log file(s)... Parsing log file(s) done Generating reports... ================================================================================ ---- Global Information -------------------------------------------------------- > request count 10000 (OK=10000 KO=0 ) > min response time 2 (OK=2 KO=- ) > max response time 176 (OK=176 KO=- ) > mean response time 4 (OK=4 KO=- ) > std deviation 7 (OK=7 KO=- ) > response time 50th percentile 3 (OK=3 KO=- ) > response time 75th percentile 4 (OK=4 KO=- ) > response time 95th percentile 7 (OK=7 KO=- ) > response time 99th percentile 12 (OK=12 KO=- ) > mean requests/sec 84.746 (OK=84.746 KO=- ) ---- Response Time Distribution ------------------------------------------------ > t < 800 ms 10000 (100%) > 800 ms < t < 1200 ms 0 ( 0%) > t > 1200 ms 0 ( 0%) > failed 0 ( 0%) ================================================================================ Reports generated in 1s. Please open the following file: /home/ec2-user/workspace/gatling/results/testmysimulation-1469251829209/index.html
テストが終わると、最後にサマリーが表示されます。
サマリーの一番下が、レポートの格納場所です。
ブラウザで http://<IPアドレス>/gatling/ にアクセスすると、レポートの一覧が表示されるので見たいレポートをクリックします。
上記実行結果のレポートは下図のとおり。
アクセス状況をグラフで見ると、徐々にアクセスが増えて、徐々にアクセスが減る山の形になっているのがわかります。
ちなみに、
テストシナリオ実行中のWEBサーバのアクセスログを見ると、以下のように表示されます。
ELBのIPアドレスが2つあるのがわかります。
ELBのIPアドレスが2つあるのがわかります。
[ec2-user@ip-10-0-11-160 ~]$ sudo tail /var/log/httpd/access_log 10.0.11.119 - - [23/Jul/2016:05:32:21 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.8 - - [23/Jul/2016:05:32:22 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.8 - - [23/Jul/2016:05:32:23 +0000] "GET /alive HTTP/1.1" 200 6 "-" "ELB-HealthChecker/1.0" 10.0.11.119 - - [23/Jul/2016:05:32:23 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.8 - - [23/Jul/2016:05:32:24 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.119 - - [23/Jul/2016:05:32:25 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.8 - - [23/Jul/2016:05:32:27 +0000] "GET /sample/hello HTTP/1.1" 200 343 "-" "-" 10.0.11.119 - - [23/Jul/2016:05:32:27 +0000] "GET /alive HTTP/1.1" 200 6 "-" "ELB-HealthChecker/1.0" 10.0.11.8 - - [23/Jul/2016:05:32:53 +0000] "GET /alive HTTP/1.1" 200 6 "-" "ELB-HealthChecker/1.0" 10.0.11.119 - - [23/Jul/2016:05:32:57 +0000] "GET /alive HTTP/1.1" 200 6 "-" "ELB-HealthChecker/1.0"