読者です 読者をやめる 読者になる 読者になる

bauer's diary

凡人の凡人による凡人のための備忘録

きたるISUCON6向け武者修行その1 -仮想環境を構築して負荷試験を実行してみよう-

強い意志の元、今年こそISUCONに参加しようと思います。

ISUCONとは?

お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトル、それがISUCON

isucon.net

そこで、まずはチームメンバーとISUCON4(2014年開催)の復習をしようということになりました。

ISUCONの過去問を構築するためのVagrantfileを用意してくださった素晴らしい方のリポジトリがあるので、そちらをベースに仮想環境を構築して進めていこうと思います。
github.com

1.Vagrantfileを準備する

前述のリポジトリをcloneし、isucon4-qualifierにcdします。
その階層にVagrantfileが用意されています。

$ git clone https://github.com/matsuu/vagrant-isucon
$ cd isucon4-qualifier


2.ローカルにVirtualBoxVagrantをインストール

ここでは手軽にbrew caskでインストールします。

$ brew cask install virtualbox
$ brew cask install vagrant

VirtualBoxは、仮想的なPCを作成し、特定のOSをインストール・実行できるソフトウェアです。
Vagrantは、仮想環境の構築と制御を行うソフトウェアです。

検証環境は下記の通りです。


3.起動・プロビジョニング

Vagrantfileがあるディレクトリで下記コマンドにて環境を構築していきます。

$ vagrant up

するとエラーが発生しました。

Failed to load R0 module /Applications/VirtualBox.app/Contents/MacOS/VMMR0.r0: World writable: '/Applications' (VERR_SUPLIB_WORLD_WRITABLE).
Failed to load VMMR0.r0 (VERR_SUPLIB_WORLD_WRITABLE).

どうやらVirtualBoxのバグらしく、下記コマンドを実行して再度vagrant upしたらすんなり通りました。

# VirtualBox.app配下全てについて、権限がないユーザ・グループ以外のユーザに対して書き換えを禁止する
$ sudo chmod -R o-w /Applications/VirtualBox.app/
# パーミッションが正しくない場合は修復する
$ sudo /usr/libexec/repair_packages --repair --standard-pkgs --volme / --debug


4.VagrantインスタンスSSHでログインする
$ vagrant ssh
Last login: Wed Jun 22 04:08:36 2016 from 10.0.2.2
[vagrant@localhost ~]$


5.isuconユーザにスイッチする
[vagrant@localhost ~]$ sudo su - isucon

# 構成はこんな感じ
[isucon@localhost ~]$ ll -lrt
total 8984
drwxr-xr-x. 4 isucon isucon    4096 Jun 22 03:10 gocode
drwxr-xr-x. 9 isucon isucon    4096 Jun 22 03:29 webapp
-rwxr-xr-x. 1 isucon isucon     428 Jun 22 03:29 init.sh
-rwxr-xr-x. 1 isucon isucon     734 Jun 22 03:29 env.sh
-rwxr-xr-x. 1 isucon isucon 9177962 Jun 22 03:29 benchmarker
drwxr-xr-x. 2 isucon isucon    4096 Jun 22 03:30 sql

この用意されたbenchmarkerを使ってサーバに負荷をかけて、スコアを競います。

6.参考実装の言語切り替え

今回我々のチームはpythonで戦う予定なので、まずはpythonベンチマークを実行してみることとします。

デフォルトがRubyになっているので、supervisordを終了させます。

Supervisorとは、常駐起動させたいスクリプトなどを容易にプロセス管理/デーモン化するツールです。

$ supervisorctl stop isucon_ruby

次に、/etc/supervisord.confを編集します。
[isucon_ruby]をautostart=falseにします。

[program:isucon_ruby]
directory=/home/isucon/webapp/ruby
command=/home/isucon/env.sh foreman start
user=isucon
stdout_logfile=/tmp/isucon.ruby.log
stderr_logfile=/tmp/isucon.ruby.log
autostart=false

切り替えたい言語をautostart=trueにします。
pythonはgunicornでHTTPサーバを立ち上げているようです。
Gunicorn - Python WSGI HTTP Server for UNIX

[program:isucon_python]
directory=/home/isucon/webapp/python
command=/home/isucon/env.sh gunicorn -c gunicorn_config.py app:app
user=isucon
stdout_logfile=/tmp/isucon.python.log
stderr_logfile=/tmp/isucon.python.log
autostart=true

最後にpythonにてsupervisordをstartさせます。

$ supervisorctl start isucon_python

supervisordは、よくあるinit.d配下での管理ではなかったことを知りました
/etc/init.d/supervisord stop
/etc/init.d/supervisord start


7.ベンチマーク実行
[isucon@localhost ~]$ ./benchmarker b
09:52:07 type:info	message:launch benchmarker
09:52:07 type:warning	message:Result not sent to server because API key is not set
09:52:07 type:info	message:init environment
09:52:10 type:info	message:run benchmark workload: 1
09:52:29 type:fail	reason:Connection timeout	method:GET	uri:/images/isucon-bank.png
09:52:39 type:fail	reason:Connection timeout	method:POST	uri:/login
09:52:49 type:fail	reason:Connection timeout	method:GET	uri:/
09:52:59 type:fail	reason:Connection timeout	method:GET	uri:/
09:53:09 type:fail	reason:Connection timeout	method:GET	uri:/
09:53:19 type:fail	reason:Request cancelled because benchmark finished (1min)	method:GET	uri:/
09:53:19 type:info	message:finish benchmark workload: 1
09:53:24 type:info	message:check banned ips and locked users report
09:54:24 type:fail	reason:Request cancelled because benchmark finished (1min)	message:Report checking is failed. Do not send score.
09:54:24 type:score	success:654	fail:6	score:142

無事pythonで実行できて、スコアも表示されたけど、failばかり…

しばらく調べてみると、pythonのプロセスがおかしいことに気づきました。

$ ps aux | grep unicorn
isucon   13124  0.0  1.6 247772 31332 ?        Sl   08:25   0:00 unicorn master -c unicorn_config.rb -p 8080
isucon   13154  0.0  2.0 259700 39108 ?        Sl   08:25   0:00 unicorn worker[0] -c unicorn_config.rb -p 8080
isucon   13157  0.0  1.9 258840 38304 ?        Sl   08:25   0:00 unicorn worker[1] -c unicorn_config.rb -p 8080

謎のunicornプロセスが起動しています。
"gunicorn"が正式名称です。

masterプロセスをkillして、再度supervisorで起動します。

$ sudo pkill -f 'unicorn'
$ supervisorctl restart isucon_python

ちゃんとgunicornのプロセスが起動しています。

$ ps aux | grep unicorn
isucon   16685  0.1  0.7 200628 14740 ?        S    10:03   0:00 /home/isucon/.local/python/bin/python2.7 /home/isucon/.local/python/bin/gunicorn -c gunicorn_config.py app:app
isucon   16690  0.0  1.0 231740 19476 ?        S    10:03   0:00 /home/isucon/.local/python/bin/python2.7 /home/isucon/.local/python/bin/gunicorn -c gunicorn_config.py app:app
…

再度ベンチマーカーを実行します。

[isucon@localhost ~]$ ./benchmarker b
10:06:04 type:info	message:launch benchmarker
10:06:04 type:warning	message:Result not sent to server because API key is not set
10:06:04 type:info	message:init environment
10:06:07 type:info	message:run benchmark workload: 1
10:07:07 type:info	message:finish benchmark workload: 1
10:07:12 type:info	message:check banned ips and locked users report
10:07:36 type:report	count:banned ips	value:1
10:07:36 type:report	count:locked users	value:2554
10:07:36 type:info	message:Result not sent to server because API key is not set
10:07:36 type:score	success:5820	fail:0	score:1258

それっぽいスコアになりました!
何もチューニングしないときのスコアは
success:5820 fail:0 score:1258
です。

8.ブラウザからいすこん銀行を表示させる

ベンチマーカーも無事動いたので、ブラウザから画面を表示してみます。
Vagrantfileのポートフォワーディング行のコメントアウトを消して有効にして、hostを8080→3333にします。

  config.vm.network "forwarded_port", guest: 80, host: 3333

Vagrantファイルを更新したので再読み込みします。

vagrant reload


これによってホストの特定ポートへのアクセスが、ゲストに転送されます。
ここではホストの3333番ポート宛のアクセスが、仮想マシンの80番ポートに転送されます。

f:id:kitakitabauer:20160713171530p:plain

無事表示されました!

9.再プロビジョニングによって設定が上書きされないようにしておく

再度vagrant upしたら、これまで変更した内容が消えてしまうので、
Vagrantfileの下記行を念のためコメントアウトしておきます。

  config.vm.provision "shell", inline: <<-SHELL
    set -e
    yum install -y epel-release git
    yum install -y ansible
    rm -rf ansible-isucon
    git clone https://github.com/matsuu/ansible-isucon.git
    (
      cd ansible-isucon/isucon4-qualifier
      PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ansible-playbook playbook.yml -i local
    )
    rm -rf ansible-isucon
  SHELL



次回から、インストールされたミドルウェアのチューニングをしていきます。
次回記事はこちら