― Web Technology and Life ―

Plack時代のReverse proxyによるサーバー運用方法 ~YAPC::Asia2010の復習(後編)~

2011-10-20
後編を書く前に、YAPC::Asia2011が終わってしまったので、変な勘違いをされるかとやめようかと思ったのですが。。。とりあえず、YAPC::Asia2010の復習として、Plack時代のPerlによるサーバ運用では、わりと一般的なリバースプロクシによる運用を、このブログの実例で報告します。

前置き:plackupはわかったけど、実際どうするの?

「Perlは遅い」の原点だったApacheのcgi時代は終わりを告げ、Apacheに依存したmod_perl時代も終りを告げました。Plackを使えば、CGIだろうとmode_perlだろうとPerlのスタンドアローンサーバーであろうと、かなり汎用的に動かせる時代です。mod_perlとかFastCGI前から使っていれば、あるいは、「Rubyではふんふん、Pythonではふんふん」とか語れれば、いろいろな歴史をしっているからすぐ実践しやすいと思うんですが、技術はちょっとわかるけど詳しくはという「モダンLL言語初心者」(perlとかcgi遅いよねーって人とか、サーバどこ?FTPのID/PASS教えてって人とか)に突然、最近のPerlはPlackを使ってStarmanやStarletとかふんふんとかいっても、かなり意味不明ですね。なので、とりあえず、動かしてみるとわかりやすいと思うので、そのために必要な、「plackup ./app.psgiはわかったけど、実際にドメインとって動かすにはどうしたらいいのよ」ってことのサンプルをこのブログを例にワンストップでまとめたいと思います。YAPC::Asia Tokyo 2011の主たる参考セッションは、Modern Perl Web Development on Amazon EC2です。

Webアプリの作り方

基本的にCGIライクに作りたいなら、Amon2のLiteフレイバー使うとモダンな拡張性も高いし、1枚ファイルでシンプルなので、是非使うといいと思います。今回のサンプルはあくまでこのブログなので、githubのhirobanex.netのソースをみてください。

apacheを使う

「とりあえず使う」には、インストールしてリバースプロクシの設定をするだけです。ちょっとした負荷にはmod_cacheをいれておくとをわりと延命されますがここでスルーします。

実際にApacheをインストールして設定

sudo aptitude install apache2 #OSはubuntuです、CentOSとかだと違うんで違うブログとかみてください
cd /etc/apache2/mods-enabled
sudo a2enmod proxy_http
sudo a2enmod proxy
sudo cp /etc/apache2/mods-available/proxy.conf /etc/apache2/mods-available/proxy.conf.bk
sudo vi /etc/apache2/mods-available/proxy.conf#設定は以下参照
sudo /etc/init.d/apache2 restart
#/etc/apache2/mods-available/proxy.confの設定
<IfModule mod_proxy.c>
#turning ProxyRequests on and allowing proxying from all may allow
#spammers to use your proxy to send email.
ProxyRequests Off
<Proxy http://localhost:5000/>
AddDefaultCharset off
Order deny,allow
Deny from all
Allow from all
</Proxy>
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
# Enable/disable the handling of HTTP/1.1 "Via:" headers.
# ("Full" adds the server version; "Block" removes all outgoing Via: headers)
# Set to one of: Off | On | Full | Block
#ProxyVia On
</IfModule>

解説

ubuntuの場合apacheは/etc/apache2に入るようです。proxyモジュールなどの有効化には、「/etc/apache2/mods-available」に入っているモジュールを「/etc/apache2/mods-enabled」にシンボリックリンクをはることで可能にします。実際には、a2enmodというコマンドツールを使用して「sudo a2enmod proxy」のようにすると自動でモジュールを使用するのに必要なシンボリックリンクがはられます。(無効にするときは、sudo a2dismod proxy)confファイルを編集するときは、念の為バックアップ用にコピーしてから編集するのが無難ですね。

damontools,plackupの設定して使う

psgiをバックエンドで動かすには、&とかつけて実行してもいいと思うんですが、damontoolsというデーモン作成ツールを使うとなぜか落ちたときに勝手に再起動するとかしてくれるから「いいね!」ということでみんなこのツールを使ってplackupしているようです。

damontoolsのインストール

sudo aptitude install daemontools
sudo aptitude install daemontools-run
cd MyApp/
mkdir daemontools
vi run #以下のdaemontools/runの設定を参照

chmod +x run
mkdir log
cd log
vi run #daemontools/log/runの設定を参照

chmod +x run
cd /etc/service
sudo ln -s /home/hirobanex/project/Hirobanex/assets/daemontools hirobanex.net
sudo /usr/bin/svscanboot &

#./deamontools/supervise,./deamontools/log/supervise/,./deamontools/log/mainが出来ているか確認

daemontools/runの設定と解説

設定

#! /bin/sh
PERL5LIB=./lib:/home/hirobanex/site_perl
export PERL5LIB

USER='hirobanex'
export USER

exec 2>&1
cd /home/hirobanex/project/Hirobanex
exec setuidgid hirobanex envuidgid hirobanex /home/hirobanex/perl5/perlbrew/perls/current/bin/start_server --port=127.0.0.1:5000 --interval=5 -- /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup -E staging -s Starlet --max_workers=4 --max-reqs-per-child=50 --max-keepalive-reqs=1 ./assets/script/hirobanex.psgi

解説と疑問

setuidgidでふんふん書いてもの環境変数がExportされないので、PERL5LIBとかみたいにいちいちエクスポートしなくてはいけません。あまり多くなったりいろんなサーバーで使うようなら、ファイルから環境変数を設定できる envfile コマンドを書いてみたを参照するといいと思います。

start_serverっていうのを使うと、アプリの機能追加の再起動とかにdaemontoolsの「sudo svc -h /etc/service/hirobanex.net」で500番を出すことなくデプロイできるとすぐれものだそうです。オプションの--port=127.0.0.1:5000っていうのをすると、5000番ポートでこのサーバーをたちあげるんだけど、127.0.0.1からしかlistenしないから外部からhirobanex.net:5000とかってアクセスできないようにする設定になります。plackupの-o 127.0.0.1 -p 5000っていうので同じことができるんですけど、start_serverを使うとこの設定は無視されるので、start_server側で設定しなくてはなりません。

plackupのそれぞれのオプションですが、-Sに使いたいサーバを指定します。いろいろあるみたいですが、とりあえず、StarmanかStarletを指定すればよさそうです。Prefork型で子プロセスを増やすことによってパフォーマンスを簡単に向上させることができます。「--max_workers=4 --max-reqs-per-child=50 --max-keepalive-reqs=1 」のところはStarlet限定です。
あと、Plackで使えるサーバーの話ですが、Plack::Server::Standalone::Prefork::Server::StarterとStarletの違いがよくわかりませんが、たぶんStarletが進化版なのだと思います。
また、Perlモジュールのコードの位置による呼び出し順の違いで-L Shotgunつけて実行していたと報告したら、nekokakさんとhide_o_55さんから怒られたのではずしました(笑)リクエストのレスポンスが飛躍的に向上しましたが、後述しますがメモリリークが発生していることがわかりました(苦笑)

daemontools/log/runの設定

#! /bin/sh
exec 2>&1
exec setuidgid hirobanex multilog t ./main

たぶんこれでいいはずですが、いろいろ再起動とかしているうちに、いつの間にかエラーログが出力されなくなっていることに気が付きました。。。(助けてーわかるひとー!)

最初は以下で設定していたのを上記に直したところうまくいきました。ちなみに、なんかlogファイルがおかしくなったときも、「sudo svc -dx /etc/service/hirobanex.net/log/」とかしながら設定ファイルをごにょごにょして、daeomontoolsを再起動させて、を繰り返せば他のケースでも試行錯誤して対応できそうですね。

#! /bin/sh
exec multilog t e 2>&1 ./main

運用Tips

daemontoolsが動いるか確認
「sudo svstat /etc/service/hirobanex.net」秒数が出ず、1,0,1,0を繰り返すと実行ファイルに間違いがるので修正します。
実行ファイルの再起動
sudo svc -dx /etc/service/hirobanex.net
実行ファイルのServer::Starter経由のホットデプロイ再起動
sudo svc -h /etc/service/hirobanex.net
日時に変換してログをみる
sudo tail -f ./main/current | tai64local
完全停止
    sudo mv /etc/service/hirobanex.net /etc/service/.hirobanex.net
    sudo svc -dx /hirobanx/assets/daemontools #シンボリックリンク先で生きているので消す
    ps aux | grep plackup #プロセスがいないことを確認
    

運用直前の調査

サービスをリリースした後に懸念になってくるのは、データの使用量、増加量でしょう。私は規模感のあるサービスの運用とかやったことがないのでよくわかりませんが、なんとなく以下が重要になってくるはずです。

  • メモリリークしていないか
  • HDDの増加スピード
  • 1プロセスあたりのi/oへの影響、あるいは、どのあたりの処理を超えるとi/oへ影響してくるか
  • 1プロセスあたりの秒間のリクエストをさばく数
  • 1プロセスあたりのメモリ使用量
  • 1プロセスあたりのCPU使用量

1プロセスあたりのメモリ使用量

とりあえず、「1プロセスあたりのメモリ使用量」とかを調べる方法の参考URLは以下。

基本的にStarletとかPreforkのPerlサーバーの場合、naoyaさんのshared_memory_size.pl のRSSとSHAREDの差分が1プロセス増やす場合のメモリ量と言えるので、この値の子プロセスの平均で--max_workers+1するかどうか判断できそうです。また、Gtopでモジュール別のメモリ使用量とか調べられるみたいですね。とりあえず、kazuhoさんの記事の値は1プロセスあたり20Mくらいだし、私が作ったO/Rマッパーつかったプロセスもだいたい20MTG前後だから、だいたい20M前後なら「まぁいいか」というラインかと。

このブログ場合の例

上記の1プロセスあたりのメモリ使用量調査法をこのブログで試した数値を例としてあげておきたいと思います。

# ps aux | grep plackup
1000     12609  0.0  1.5  34584  7612 ?        S    Oct16   0:00 /home/hirobanex/perl5/perlbrew/perls/perl-5.10.1/bin/perl /home/hirobanex/perl5/perlbrew/perls/current/bin/start_server --port=127.0.0.1:5000 --interval=5 -- /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup -E staging -s Starlet --max_workers=4 --max-reqs-per-child=50 --max-keepalive-reqs=1 ./assets/script/hirobanex.psgi
1000     16053  0.0  2.3  61584 11932 ?        S    Oct16   0:00 /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup
1000     22730  0.0  0.1   7188   940 pts/0    S+   08:43   0:00 grep --color plackup
1000     32043  0.0  5.9 108328 30256 ?        S    Oct19   0:02 /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup
1000     32070  0.0  5.9 108092 30124 ?        S    Oct19   0:02 /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup
1000     32071  0.0  6.0 108412 30344 ?        S    Oct19   0:02 /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup
1000     32072  0.0  5.9 108216 30220 ?        S    Oct19   0:01 /home/hirobanex/perl5/perlbrew/perls/current/bin/plackup

基本的に、30Mくらいに表示されていますね。psのRSS値はC/Wの共用メモリ込み値らしいので、ちょっと高めに出ています。

#sudo perl -le 'for my $p (@ARGV) { open my $fh, "< /proc/$p/smaps" or die $!; map { /^Pss:\s*(\d+)/i and $s += $1 } <$fh> } print $s' `pgrep plackup`
105115

plackupしている全体のメモリ量は、100Mくらいですね。子プロセスは増やせますね。

#shared_memory_size.pl `pgrep plackup` || shared_memory_size.plのコードはnaoyaさんの記事参照
PID     RSS     SHARED
16053   11932   6096 (51%)
32043   30256   6964 (23%)
32070   30124   6964 (23%)
32071   30344   6964 (22%)
32072   30220   6964 (23%)

plackupの各プロセスの実メモリは、23Mくらいでしょうか。子プロセスを1つ増やすには、だいたい23Mくらい必要ということですね。

メモリリークの調査

根本的に、この「運用直前の調査」のまとめをしているのは、このブログのバックエンドのサーバープロセスが上述のデータの通りメモリリークしているっぽい気がしたからです。で、メモリリーク疑惑を解消しようと思ったけど、ここで体力がつきたので、とりあえず、Starletのオプションの--max-reqs-per-childを少なくして、しのぎました(笑)

【追記】
Hokkaido.pmでhirataraさんが発表されていた『循環参照のはなし』が、メモリリークの調査や「そもそもPerlのメモリリークって?」という話が詳しく書かれていてとても参考になりますね!とても、素晴らしいです!実践してみたら、ここに追記します。

【追記:2012-03-26】
『Webアプリのパフォーマンスアップ作戦』に、どれだけリクエストをさばけるかの計測方法や、クライアント側の体感スピードの計測方法が載っていて参考になりそうです。

最後に

まぁ、こぴぺすれば一瞬ですね!楽チンですね!実際、この適当なブログとかは、daemontoolsとかは使わなくて&でバックグラウンド実行すればいいし、メモリリークしても子プロセスの処理数を減らせばいいし。笑。要件に合わせて前に進むのが大事ですね。
とはいうものの、ちゃんと理解して使いたい、使いこなしたい、しっかりとドキュメントみて、ふんふんしなくて理解できませんね。Plackについて書いてある本が『CPANモジュールガイド』くらいしかないから、Web+DB Pressの総集編とか、cpan.orgとかのドキュメントを追っていかないと厳しいのが、まだまだ初心者には厳しいですね。。。

また、個人的な問題としては、以下を解決しなくてはいけないのが、わかりました・・・

  • daemontoolsのログが出なくなっったのが問題こちらは上述したとおりリカバリーできました
  • メモリリーク問題

YAPC::Asiaにいって、やる気もらうのもいいですが、実際に、セッションで聞いた実用的なことがあったらやる気のあるうちに実践するのがいいし、プロダクトだったら、使ってみるのがいいしソース読んでみるのがいいですね!今年の場合は、DBIx::HandlerとかCartonとか触ってみようと思っていますよ!

Perl このブログについて update_at : 2013-05-29T14:18:56
hirobanex.netの更新情報の取得
 RSSリーダーで購読する   
blog comments powered by Disqus