php-fpmを使ってphpを快適にfastcgiで実行する

#fpmを使ってphpをfastcgiで実行する
phpをモジュール版ではなくcgi版でインストールしたが、そのまま使うとパフォーマンスの心配もあり、またセキュリティ的にも不安なのでphp-fpmを使用してfastcgiで実行する。

cgi版をそのまま使用すると一つのプロセスを１処理で使って破棄、また処理の要求があった時にプロセスを作成して・・・といった無駄なオーバーヘッドがあり非常にコストがかかる事になってしまいます。それに対してphp-fpmだとプロセスを使いまわししてくれます。そのため、オーバーヘッドがなくなるばかりか、モジュール版でなくともopcacheが効くようになるという効果も得る事ができます。

更にモジュール版と違ってサイトごとに実行ユーザを変更するなど色々調整ができます。大変使いやく応用が効きますのでおススメです。
※モジュール版でも各サイト毎にWEBサーバを立ち上げ、リバースプロキシを使えば実現できるのですが、、fpmのようにお手軽ではないと考えています。

##php-fpmのインストール
php5.6を既にインストールしてる前提です。
今回はopcacheも一緒に入れました。使用しているサーバがawsなのでamazonのリポジトリに5.6がありました。もしも5.6がない場合はremi-php56リポジトリなどを使ってください。

`yum install php56-opcache.x86_64 php56-fpm.x86_64`

##設定
yumのパッケージでインストールした場合、設定ファイルは
/etc/php-fpm.conf
と
/etc/php-fpm.d/配下に置いた*.confが使用されます。
今回はセキュリティを上げたいので各ドメインごとにphpの実行ユーザを分けたいと思います。
また、本来なら専用のサーバを用意したいのですが・・趣味なのでWEBサーバと同じサーバに入れます。
その為、ソケット通信にしています。

具体的には下記のような構成を実現します。

|ドメイン名|www.hoge.jp|www.hoge.com|
|:---|:----|:----|
|ポート|socket通信|socket通信|
|アクセス許可|localhost|localhost|
|実行ユーザ|www.hoge.jp|www.hoge.com|
|ドキュメントルート|/var/www/www.hoge.jp/doc_root/|/var/www/www.hoge.com/doc_root/|
|phpログフォルダ|/var/www/www.hoge.jp/log/|/var/www/www.hoge.com/log/|
|sessionフォルダ|/var/www/www.hoge.jp/session/|/var/www/www.hoge.com/session/|
|SOAPキャッシュフォルダ|/var/www/www.hoge.jp/session/|/var/www/www.hoge.com/wsdlcache/|

###設定パラメータ
pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_serversは負荷テストなどをしながら調整するしかないと思います。
サイトやサーバーごとによって変わると思うので絶対的な正解はないと思います。

|パラメータ名|説明|
|:--|:--|
|[xxx]|プロセスプールになります。このプールの単位でlistenや実行ユーザの切り替えが可能です。今回はドメインごとにプールを切り分けます。|
|listen|FastCGI リクエストを受け入れるアドレス。 'ip.add.re.ss:port', 'port', '/path/to/unix/socket' 形式の構文が使えます。 このオプションは、各プール単位で必須となります。|
|listen.allowed_clients|接続を許可されている FastCGI クライアントの ipv4 アドレス一覧。オリジナル版 PHP FastCGI (5.2.2+) における環境変数 FCGI_WEB_SERVER_ADDRS と同じです。 tcp でリスンするソケットに対してのみ意味をなします。 書くアドレスはカンマ区切りで指定します。この値を空にしておくと、任意の ip アドレスからの接続を許可します。 デフォルト値: 任意の ip アドレスを許可。|
|listen.owner|unix ソケットを使う場合に、そのパーミッションを設定します。Linux では、 読み書きアクセス権限を設定しないとウェブサーバーからの接続を受け付けることができません。 デフォルト値: ユーザーとグループは実行しているユーザーと同じ、モードは 0660|
|listen.group|listen.ownerと同じ。socketのパーミッション。|
|listen.mode|listen.ownerと同じ。socketのパーミッション。|
|||
|user|FPM プロセスの unix ユーザー。このオプションは必須です。セキュリティの為にも専用ユーザを用意した方が良いと思います。|
|group|FPM プロセスの unix グループ。未設定の場合は、デフォルトのユーザーのグループを使います。セキュリティの為にも専用グループを用意した方が良いと思います。|
|||
|pm|プロセスマネージャが子プロセスの数を制御する方法を選択します。 使用可能な値: static, ondemand, dynamic このオプションは必須です。|
|pm.max_children|pm が static の場合は作成される子プロセスの数、 pm が dynamic の場合は作成される子プロセスの最大数。 このオプションは必須です。このオプションは、同時に処理できるリクエストの最大数を設定します。 mpm_prefork での ApacheMaxClients ディレクティブみたいなイメージです。|
|pm.start_servers|起動時に作成される子プロセスの数。pm が dynamic の場合にのみ使います。デフォルト値: min_spare_servers + (max_spare_servers - min_spare_servers) / 2|
|pm.min_spare_servers|アイドル状態のサーバープロセス数の最小値。 pm が dynamic の場合にのみ使います。 また、この場合には必須となります。アイドル状態のプロセス数がこれよりも減った場合に新たなプロセスが作成されます。|
|pm.max_spare_servers|アイドル状態のサーバープロセス数の最大値。 pm が dynamic の場合にのみ使います。 また、この場合には必須となります。アイドル状態のプロセス数がこれよりも増えた場合にアイドルなプロセスをkillします。|
|pm.max_requests|各子プロセスが、再起動するまでに実行するリクエスト数。 サードパーティのライブラリにおけるメモリリークの回避策として便利です。 再起動せずにずっとリクエストを処理させる場合は '0' を指定します。 PHP_FCGI_MAX_REQUESTS と同じです。デフォルト値: 0|
|||
|pm.status_path|FPM の情報ページを見るための URI。この値を省略した場合は、どの URI も情報ページとは見なされません。デフォルト値: なし|
|ping.path|FPM のモニタリングページをコールするための ping URI。この値を省略した場合は、どの URI も ping ページとは見なされません。これを使うと、 FPM が生きていて応答するかどうかを外部から確かめることができます。 この値の最初はスラッシュ (/) で始めなければならないことに注意しましょう。|
|||
|request_terminate_timeout|単一のリクエストを処理する際のタイムアウト。この時間を過ぎるとワーカープロセスが kill されます。 このオプションは、'max_execution_time' ini オプションが何らかの理由でスクリプトの実行を止められなかった場合に使われます。 値 '0' は 'Off' を意味します。 使用可能な単位: s(秒)(デフォルト), m(分), h(時間) あるいは d(日)、 デフォルト値: 0|
|request_slowlog_timeout|単一のリクエストを処理する際のタイムアウト。この時間を過ぎると PHP のバックトレースが 'slowlog' ファイルに出力されます。 値 '0' は 'Off' を意味します。 使用可能な単位: s(秒)(デフォルト), m(分), h(時間) あるいは d(日)、 デフォルト値: 0|
|slowlog|遅いリクエストを記録するログファイル。デフォルト値: #INSTALL_PREFIX#/log/php-fpm.log.slow|
|||
|php_admin_flag|このドメイン独自で設定したい値をここに書くことができます。php.iniの設定を上書きするイメージです。|
|php_admin_value|このドメイン独自で設定したい値をここに書くことができます。php.iniの設定を上書きするイメージです。|
|php_value|このドメイン独自で設定したい値をここに書くことができます。php.iniの設定を上書きするイメージです。|
|||

###ユーザ、ディレクトリの追加
ユーザはセキュリティ向上の為、ログインできないユーザにしておきます。

`mkdir -p /var/www/www.hoge.jp/log`
`mkdir -p /var/www/www.hoge.jp/doc_root`
`mkdir -p /var/www/www.hoge.jp/session`
`mkdir -p /var/www/www.hoge.jp/wsdlcache`

`mkdir -p /var/www/www.hoge.com/log`
`mkdir -p /var/www/www.hoge.com/doc_root`
`mkdir -p /var/www/www.hoge.com/session`
`mkdir -p /var/www/www.hoge.com/wsdlcache`

`groupadd -g 2000 www.hoge.jp`
`groupadd -g 2001 www.hoge.com`

`useradd -u 2000 -g 2000 -N -s /sbin/nologin -M -d /var/www/www.hoge.jp www.hoge.jp`
`useradd -u 2001 -g 2001 -N -s /sbin/nologin -M -d /var/www/www.hoge.com www.hoge.com`

`chown -R www.hoge.jp:www.hoge.jp /var/www/www.hoge.jp`
`chown -R www.hoge.com:www.hoge.com /var/www/www.hoge.com`

###/etc/php-fpm.d/配下の設定ファイル
/etc/php-fpm.d/配下にドメインごとに設定ファイルを用意します。
（一つのファイルに複数のサーバを記載する事も可能です。）


```lang:/etc/php-fpm.d/www.hoge.jp.conf
[www.hoge.jp]
listen = /var/run/php-fpm/www.hoge.jp.sock
;listen.allowed_clients = 127.0.0.1
listen.owner = nginx
listen.group = nginx
listen.mode = 0600

user = www.hoge.jp
group = www.hoge.jp

pm = dynamic
pm.max_children = 40
pm.start_servers = 3
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 10000
pm.status_path = /operation/php-fpm/www.hoge.jp-status.php
ping.path = /operation/php-fpm/www.hoge.jp-ping.php

request_terminate_timeout = 600
request_slowlog_timeout = 100
slowlog = /var/www/www.hoge.jp/log/php-fpm/php-slow.log

php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/www/www.hoge.jp/log/php-fpm/php-error.log
php_value[session.save_handler] = files
php_value[session.save_path] = /var/www/www.hoge.jp/session
php_value[soap.wsdl_cache_dir]  = /var/www/www.hoge.jp/wsdlcache
```

```lang:/etc/php-fpm.d/www.hoge.com.conf
[www.hoge.com]
listen = /var/run/php-fpm/www.hoge.com.sock
;listen.allowed_clients = 127.0.0.1
listen.owner = nginx
listen.group = nginx
listen.mode = 0600

user = www.hoge.com
group = www.hoge.com

pm = dynamic
pm.max_children = 40
pm.start_servers = 3
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 10000
pm.status_path = /operation/php-fpm/www.hoge.com-status.php
ping.path = /operation/php-fpm/www.hoge.com-ping.php

request_terminate_timeout = 600
request_slowlog_timeout = 100
slowlog = /var/www/www.hoge.com/log/php-fpm/php-slow.log

php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/www/www.hoge.com/log/php-fpm/php-error.log
php_value[session.save_handler] = files
php_value[session.save_path] = /var/www/www.hoge.com/session
php_value[soap.wsdl_cache_dir]  = /var/www/www.hoge.com/wsdlcache
```

###nginx側
nginx側はソケット通信を用いるので下記のようにします。

```lang:www.hoge.jpドメイン
fastcgi_pass   unix:/var/run/php-fpm/www.hoge.jp.sock;
```

```lang:www.hoge.comドメイン
fastcgi_pass   unix:/var/run/php-fpm/www.hoge.com.sock;
```

###番外編apacheの場合
proxy_fcgi_moduleが使えるならproxy_fcgi_moduleを使おう
（2.4〜）

```lang:mod_fastcgiの場合
   FastCGIExternalServer /usr/sbin/php-fpm -socket /var/run/php-fpm/www.hoge.com.sock
```


```lang:proxy_fcgi_moduleの場合
   SetHandler  "proxy:unix:/var/run/php-fpm/www.hoge.com.sock|fcgi://localhost"
```

#参考／抜粋／出典元
http://php.net/manual/ja/install.fpm.php

以上