Apache Passengerの設定項目について調べた

PassengerRailsを動かす事ができるアプリケーションサーバである。
Apache版の設定項目について調べたので自分用の備忘録として残しておく。

バージョン

Passenger-4.0.37
http://www.modrails.com/documentation/Users%20guide%20Apache.html

Configuring Phusion Passenger

PassengerRoot

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerroot_lt_directory_gt
apacheのpassengerモジュールの置いてあるディレクトリを指定する。
普通はインストーラを実行した時に表示されるのでそれを使えばよい。rubyのインストール場所をかえた場合などはこちらの値も変更する必要がある。

PassengerDefaultRuby

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerDefaultRuby
アプリケーションとInternalHelper(例:PassengerPreStart)が使うRubyインタプリタを指定する。
PassengerRoot同様にインストーラ実行時に表示されるのでそれを使えば良い。

Deployment options

PassengerEnabled

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerEnabled
指定したコンテクストでPassengerを無効化出来る。

PassengerRuby

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerRuby
VirtualHostやDirectory等のコンテクストで使うRubyインタプリタを指定できる。PassengerDefaultRubyをOverrideできる。
この設定ができることにより、アプリケーション毎に使うRubyのバージョンを混在することが可能になる。
ただし、InternalHelperスクリプトは常にPassengerDefaultRubyで指定されたインタプリタを使う。

PassengerPython

PassengerRubyと同じ。

PassengerNodejs

PassengerRubyと同じ。

PassengerAppEnv

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerAppEnv
下記の環境変数を指定する。stagingなど指定することでアプリケーションの環境を切り替える事ができる。
RAILS_ENV
RACK_ENV
WSGI_ENV
NODE_ENV
PASSENGER_ENV

RailsEnv

PassengerAppEnvのエイリアス

RackEnv

PassengerAppEnvのエイリアス

PassengerAppRoot

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerAppRoot
アプリケーションのルートディレクトリを指定する。
デフォルトはDocumentRootの親ディレクトリ

PassengerRestartDir

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerrestartdir_lt_directory_gt
アプリケーションを再起動するためにはrestart.txtをtouchする必要がある。
restart.txtを配置するディレクトリを指定する。
デフォルトはPassengerAppRoot配下のtmpディレクトリ。

PassengerRollingRestarts(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerRollingRestarts

OSS版の最大の弱点と言っても過言ではないのがdeploy後のダウンタイムである。Rolling Restartをonにすることでunicornのようにゼロダウンタイムdeployが可能になる。

通常のRestartの場合、workerプロセスを一度全てshutdownしてから新しいプロセスを作るのに対して、1プロセスずつ入れ替えてdeployしてくれるのがRollingRestartsである。

Phusion Passenger Enterprise: rolling restarts from Phusion on Vimeo.

PassengerResistDeploymentErrors(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerResistDeploymentErrors
DeployしたコードにSyntaxErrorなどがあった場合、壊れたコードは実際には使われずにDeploy前のバージョンが使われてDeployに失敗した事がログに出力される。
この機能はRollingRestart機能が有効になっていないと作動しないので注意が必要だ。

Phusion Passenger Enterprise: deployment error resistance from Phusion on Vimeo.

Process spawning options

PassengerSpawnMethod

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerSpawnMethod
worker生成の方法を指定する。
smartとdirectがありsmartはアプリケーションコードをcacheするために生成がdirectに比べて速いが、アプリがMemcachedとのコネクションを持っている場合などは注意が必要になる。
RailsMemcachedを使っている場合は下記設定をアプリのコードに書いてworkerプロセス毎に再接続を行う必要がある。

if defined?(PhusionPassenger)
    PhusionPassenger.on_event(:starting_worker_process) do |forked|
        if forked
            # We're in smart spawning mode.
            reestablish_connection_to_memcached
        else
            # We're in direct spawning mode. We don't need to do anything.
        end
    end
end
PassengerLoadShellEnvvars

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerLoadShellEnvvars
シェルがbashの場合、環境変数をロードする。

Security options

PassengerUserSwitching

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerUserSwitching
全てのPassengerプロセスを同一のユーザーにしないことでセキュリティを担保する

PassengerGroup

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerGroup
Passengerのプロセスはデフォルトではconfign/enviroment.rbかconfig.ruファイルの所有グループを引き継ぐが、
この設定を入れることで上書きすることができる。

PassengerDefaultUser

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerDefaultUser
user switching supportが失敗した またら無効の場合に、このオプションで指定したユーザーでプロセスが動く。
デフォルトはnobody。

PassengerDefaultGroup

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerDefaultGroup
user switching supportが失敗した またら無効の場合に、このオプションで指定したグループでプロセスが動く。
デフォルトはPassengerDefaultUserのグループ。

PassengerFriendlyErrorPages

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerFriendlyErrorPages
Passengerを立ち上げる時にDBの設定が間違っていたりすると立ち上げに失敗してエラーの原因をbacktraceとともに下記のような画面を表示してくれて嬉しいのだが、
f:id:hakutoitoi:20140308174011p:plain
プロダクション環境でこのメッセージを表示してしまうとサーバの情報を外部に漏らす可能性がある。この設定をoffにすることで非表示にできる。

Resource control and optimization options

下記動画にあるように、Enterprise版だとより柔軟なリソースコントロールが可能になる。

Phusion Passenger Enterprise: resource control from Phusion on Vimeo.

PassengerMaxPoolSize

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxPoolSize
1つのサーバで立ち上がるWorkerプロセスの最大値を設定する。
マルチスレッドモデルを使わない場合はこの数値がPassengerが同時に処理することができるリクエスト数になる。
サーバのメモリが足りない場合は数値を下げる必要がある。
デフォルトは6。
3に指定した場合、立ち上がるworkerプロセスはサーバ内で最大でも3個までとなる。

$ ps aux | grep "[P]assenger RackApp"
u     3778  5.0  6.3 141180 109172 ?       Sl   07:20  11:25 Passenger RackApp: /var/www/test-app/current
u    27640  3.6  6.3 141560 109604 ?       Sl   03:21  16:54 Passenger RackApp: /var/www/test-app/current
u    29392  3.9  6.4 142200 111356 ?       Sl   04:07  16:38 Passenger RackApp: /var/www/test-app/current

QueueSizeという名前が混乱を招くがworkerプロセスの数を意味する。
設定の目安はPhusionのブログに書いてあり、
http://blog.phusion.nl/2013/03/12/tuning-phusion-passengers-concurrency-settings/
シングルスレッドの場合の計算式:

max_app_processes = (TOTAL_RAM * 0.75) / RAM_PER_PROCESS

サーバのメモリが1.7GBで1プロセスのメモリ使用が100MBの場合は:
12.75 = (1700MB * 0.75) / 100MB

マルチスレッドの場合の計算式:

max_app_threads_per_process = ((TOTAL_RAM * 0.75) - (NUMBER_OF_PROCESSES * RAM_PER_PROCESS * 0.9)) / (RAM_PER_PROCESS / 10)
NUMBER_OF_PROCESSESはRuby(MRI)の場合CPUの数で考えていいようだ(JRUBYやRubiniusの場合は1で考える)。

Rubyを使っていてサーバのCPUが2でメモリが1.7GBで1プロセスのメモリ使用が100MBの場合は:
109.5 = ((1700MB * 0.75) - (2 * 100MB * 0.9)) / (100MB / 10)

※32bitシステムの場合はmax_app_threads_per_processは200より大きくするべきではない

上記の計算結果を設定してあげればよい。

#シングルスレッドの場合:
PassengerMaxPoolSize 12

# マルチスレッドの場合
PassengerMaxPoolSize 2(CPUの数)
PassengerThreadCount 109
PassengerMinInstances

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMinInstances
全体または1つのアプリケーションで立ち上げるWorker数の下限をglobalとアプリケーションどちらにでも指定する事が可能。

PassengerMaxInstances(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxInstances
全体または1つのアプリケーションで立ち上げるWorker数の上限をglobalとアプリケーションどちらにでも指定する事が可能。
例えば、websiteとblogをvirtulhostに設定していてwebsiteへのアクセスが多い場合は下記のように設定することでwebsiteの同時実行処理リクエスト数を2にするといったカスタマイズが可能である。

PassengerMaxRequestQueueSize 3
<VirtualHost *:80>
    PassengerMaxInstances 2
    RailsEnv production
    ServerName www.hakutoitoi.com
</VirtualHost>
<VirtualHost *:80>
    PassengerMaxInstances 1
    RailsEnv production
    ServerName blog.hakutoitoi.com
</VirtualHost>

プロセスリスト:

$ ps aux | grep "[P]assenger RackApp"
u     3778  5.0  6.3 141180 109172 ?       Sl   07:20  11:25 Passenger RackApp: /var/www/website/current
u    27640  3.6  6.3 141560 109604 ?       Sl   03:21  16:54 Passenger RackApp: /var/www/website/current
u    29392  3.9  6.4 142200 111356 ?       Sl   04:07  16:38 Passenger RackApp: /var/www/blog/current
PassengerMaxInstancesPerApp

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengermaxinstancesperapp_lt_integer_gt
一つのアプリケーションで立ち上げるWorkerプロセスの上限をグローバルで指定する事が可能。
PassengerMaxInstancesのようにアプリケーションごとに柔軟にプロセス数を指定することはできないので全てのアプリケーションの最大プロセス数は同一になる。

PassengerMaxRequestQueueSize 2
PassengerMaxInstancesPerApp 1
<VirtualHost *:80>
    RailsEnv production
    ServerName www.hakutoitoi.com
</VirtualHost>
<VirtualHost *:80>
    RailsEnv production
    ServerName blog.hakutoitoi.com
</VirtualHost>

プロセスリスト:

$ ps aux | grep "[P]assenger RackApp"
u     3778  5.0  6.3 141180 109172 ?       Sl   07:20  11:25 Passenger RackApp: /var/www/website/current
u    27640  3.6  6.3 141560 109604 ?       Sl   03:21  16:54 Passenger RackApp: /var/www/blog/current
PassengerPoolIdleTime

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerPoolIdleTime
1つのwokerが設定した秒数の間idle状態が続いた場合、そのworkerはメモリ節約のためshutdownされる。
デフォルトは300秒。
idle状態がどのくらい続いてるかはpassenger-statusコマンドのLast usedの項目で確認できる。

$ sudo /usr/local/bin/passenger-status  | grep -B 1 "Last used"
  * PID: 27640   Sessions: 0       Processed: 14570   Uptime: 9h 10m 6s
    CPU: 3%      Memory  : 103M    Last used: 23s ago
  * PID: 29392   Sessions: 0       Processed: 14477   Uptime: 8h 24m 0s
    CPU: 4%      Memory  : 104M    Last used: 4m 40s ago

この例だとPID29392のworkerがidle状態のまま4分40秒経っているためもうすぐshutdownされる。

PassengerMaxPreloaderIdleTime

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxPreloaderIdleTime
workerを生成・破棄するSpawnerプロセスがshutdownするまでのidle時間の設定。
デフォルトは300秒で、その間workerプロセスに変動がなければshutdownされる。

PassengerStartTimeout

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerstarttimeout_lt_seconds_gt
workerプロセスの開始に設定した秒数以上かかったら失敗する。
デフォルト90秒。

PassengerConcurrencyModel(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerConcurrencyModel
マルチスレッドモデルを有効にできる。

PassengerThreadCount(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerThreadCount
マルチスレッドが有効な時に一つのプロセスがいくつのスレッドを使えるようにするか設定する。
デフォルトは1。

PassengerMaxRequests

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxRequests
ここに設定したリクエスト数を処理するとwokerプロセスが再起動する。
アプリケーションがメモリリークを起こしている場合には必要な設定だろう。
デフォルトは0で無効になっている。

PassengerMaxRequestTime(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxRequestTime
リクエストの処理時間が設定値を超えたらworkerを再起動する。
デフォルトは0で無効になっている。
リクエストの処理に時間がかかりすぎてアプリケーション全体がつまって止まってしまう危険性を減らす事ができる。
下記の設定をすると/expensive_computationへのリクエストだけtimeoutまでの時間を伸ばせるといった柔軟な設定を行える。

<VirtualHost *:80>
    ServerName www.example.com
    DocumentRoot /webapps/my_app/public

    PassengerMaxRequestTime 2
    <Location /expensive_computation>
        PassengerMaxRequestTime 10
    </Location>
</VirtualHost>

この設定が必要になる時は大体アプリケーションが遅いことに問題があるので、問題を特定して迅速に修正すべきだろう。

PassengerMemoryLimit(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMemoryLimit
ここに指定したメモリ数を超えるメモリをwokerプロセスが使うと再起動する。
アプリケーションがメモリリークを起こしている場合には必要な設定だろう。
デフォルトは0で無効になっている。

PassengerStatThrottleRate

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerstatthrottlerate_lt_integer_gt
設定ファイル(config/envrironment.rb)や再起動ファイル(restart.txt)をチェックするタイミングを指定できる。
0の場合は各リクエストを処理するタイミングで行う。
秒数を指定した場合はその秒数毎にチェックする。

PassengerPreStart

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerPreStart
デフォルトではPassengerは最初にリクエストがあるまでプロセスをstartさせない。この設定を入れることでapacheを起動した時に指定したURLだけはアクセスがなくてもアプリケーションを事前にstartしてくれる。

PassengerHighPerformance

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerHighPerformance
onに設定すると少し高速化されるがmod_rewriteやmod_autoindexなどのモジュールが使えなくなる。

Connection handling options

PassengerBufferUpload

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerBufferUpload
onの場合、POSTでアップロードされたデータはアプリケーションに送られる前にバッファされる。遅いクライアントからのアップロードを守るが、アップロード進捗を追跡する機能は使えなくなる。
デフォルトはon。

PassengerBufferResponse

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerBufferResponse
onの場合、apacheにレスポンスをバッファさせる。

apache版のPassengerの場合、2つのレスポンスバッファリングシステムが有効である。

  • Apache response buffering system(PassengerBufferResponseでon/offできる)
  • Phusion Passenger response buffering system(この設定はPassengerBufferResponseがoffでも常に有効である)

基本的にはPassengerのほうがバッファしてくれるので遅いクライアントからの攻撃があってもoffで問題はない。
もし何がしかの理由でapacheレベルのバッファリングをしたい場合は、このオプションをonにすることで有効にすることができる。

注意して欲しいのはこのオプションをonにした場合はストリーミングレスポンスを作るのが不可能になること。
下記のコードは1秒毎にレスポンスを返すコードだがPassengerBuggerResponseをonにした場合は10秒後に全体のレスポンスを返す挙動になってしまう、offの場合なら期待通りに動く。

render :text => lambda { |response, output|
    10.times do |i|
        output.write("entry #{i}\n")
        output.flush
        sleep 1
    end
}

※大きいサイズのレスポンスを返す場合はこの設定はoffにすべきだろう、なぜならレスポンスはメモリにバッファされるのでメモリ使用量が極端に大きくなってしまう。

PassengerErrorOverride

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerErrorOverride
400番以上のエラーページをPassengerデフォルトのものから自分の好きなページに変更できる。

PassengerMaxRequestQueueSize

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxRequestQueueSize
全てのwokerがリクエスト処理中の状態で新規のリクエストがくるとリクエストキューに格納されてidleになったwokerが順次このキューにたまったリクエストを処理するのだがこのキューの最大サイズをアプリケーション毎に設定できる。
デフォルトは100で、100を超えたらキューにはためずにクライアントに503エラーを返すようになる。
この動作は非常に重要でアプリケーションになんかしらの問題が起きている事を把握できる。例えば:

  • PVがいきなり増加した
  • フルテーブルスキャンやフルインデックススキャン等の非常に時間のかかる処理を行うようになった
  • 巨大なテーブルにインデックスの追加を行ったため、テーブルにWRITEロックがかかり全てのwokerが更新処理中でロック解除待ちになっている

などなど。

キューにたまっているリクエスト数はpassenger-statusコマンドで知ることができる。

$ sudo /usr/local/bin/passenger-status  | grep "Requests in queue"
  Requests in queue: 0

この例ではキューはたまってないことを意味する。

また下記設定を追加することで503エラーページをカスタマイズすることが可能である。

PassengerErrorOverride on
ErrorDocument 504 /error504.html

Compatibility options

PassengerResolveSymlinksInDocumentRoot

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerResolveSymlinksInDocumentRoot
Passenger-2.2以降の場合、DocumentRootがシンボリックリンクだった場合にconfig/environment.rbを探せないが、
この設定をonにすることで2.2以前の動作になるので探せるようになる。
新しいアプリケーションに関してはDocumentRootはシンボリックにしないほうがいいだろう。

PassengerAllowEncodedSlashes

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerallowencodedslashes_lt_on_off_gt
スラッシュがURLencodeされたリクエストを処理できるようにする。

Logging and debugging options

PassengerLogLevel

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerLogLevel
ログレベルを指定する。

  • 0: errorとwarningのみ
  • 1: important debugも表示
  • 2: debugをもっと表示
  • 3: さらにdebugを表示
PassengerDebugLogFile

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerdebuglogfile_lt_filename_gt
デバッグとエラーログを出力するファイルを変更できる。
デフォルトではapacheのグローバルなerrorlogになっている。

PassengerDebugger(enterprise限定)

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerdebugger_lt_on_off_gt
Passengerでデバッガを使うことができる。
Rails開発の場合、ローカルのmacwebrickを立ち上げて行う事が多い。その時にデバッグするのと同じようにPassengerを使っている場合でもデバッグできるようになる。
デフォルトはoff。

Phusion Passenger Enterprise: live IRB and debugging console from Phusion on Vimeo.

Advanced options

PassengerTempDir

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerTempDir
Passengerが使うtmpファイルを置くディレクトリを指定できる。
デフォルトは/tmp。
この値を変更している場合は、passenger-status等のコマンドを使う場合に環境変数でディレクトリを指定しなければならない。

export PASSENGER_TMPDIR=/my_temp-dir
sudo -E passenger-status
# The -E option tells 'sudo' to preserve environment variables.
PassengerUploadBufferDir

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerUploadBufferDir
大きいファイルをPOSTされた場合に、Passengerはデータをファイルにバッファする。
そのディレクトリを指定する。
デフォルトはシステムのtmpディレクトリのサブディレクトリになる(PassengerTempDirを指定している場合はそのサブディレクトリ)。

Deprecated or removed options

Deprecatedなので割愛する。

まとめ

OSS版とEnterprise版があるが同じような設定で動かす事ができる、また Enterprise版にだけ有効な設定が多数ある。
Enterprise版では下記の機能が使えるようになる。

  • ゼロダウンタイムデプロイ
  • バグを含んだコードをデプロイした場合、それを検知できた場合ユーザーに表示させない機能
  • 柔軟なリソースコントロール
  • ライブデバッガー

Enterprise版ではダウンタイムなしでデプロイができるのでWebサービスなどで使う場合はこちらを選択すべきだろう、逆に個人的なWebサイトやブログならOSS版で十分である。