Open11

Nginx + PHP-FPM が動く理由調べたらソケット通信やロードバランサの知識も深まった

surabowsurabow

そもそもApacheじゃダメなのかと思ったけど、まず得意なことが違うらしい。
NginxはHTTPリクエストを返すことに特化してるから、Nginxのプロセスの中でPHPを実行するとかは出来ないらしい。逆にApacheはPHPやらRubyをプロセスの中で実行できる。

NginxとApacheをわかりやすく比較、Nginxが「絶対王者」のApacheを超えたワケ 連載:サーバ自動化の勘所|ビジネス+IT

ただ、Apacheは処理ができる分、PHP処理が同時に多数来ると 処理可能数 < リクエスト数 となりやすくなる。特にPHP処理が重いとかだと死ぬ。

そこでNginxをプロキシサーバーとして立てて、アプリケーションへのリクエストだけAPサーバー(Apache)が処理する、みたいにすると負荷を軽くできるとのこと。

surabowsurabow

nginx と PHP-FPM の通信はどうなってんの? - nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築する - Qiita

で、あった。
ソケット通信とやらでPHP-FPMとNginxが通信してるらしい。ソケット通信、名前しか理解してないねぇ…

ソケット - 国立情報学研究所
どうやらTCP, UDP とプログラムとの仲介を担っていて、実態としてはファイルに対する入出力のような感じでできるらしい。

調べなきゃ寝れない!と調べたら余計に寝れなくなったソケットの話 - Qiita
これを見ると、UNIXドメインソケットは同一マシン上でのみ成立するっぽい。
で、理由としてはファイルの入出力を通じて処理をしている関係でそのファイル自体がマシンを超えることを想定してないからだと思う。

surabowsurabow

でもDockerでやってるときはphp-fpmでやってて、Apache実行してる様子はなかった。
単純にdockerだから成り立ってる…ってことは無いよね。
気になるのは socket を共有してる点。そこにヒントがありそう。

つまりNginxをプロキシサーバとして使いつつ、PHP-FPMとソケット通信でPHPを実行するためにsocketを共有していた、というのが真相っぽい。

surabowsurabow

ただ、そうなるとこれは本番環境では使えない方法になるかな?
ホストマシンのファイルを各イメージに共有してるから、ホストマシンがある前提の仕組みな気がする。

…と思って調べたところ、別に出来るっちゃ出来るらしいけどjsとか画像ファイルのロードとかで別の問題が発生するらしい。
PHP WebアプリケーションのDocker本番運用を考える | blog.potproject.net
まあこれはDocker本番運用のときに考えることだな。

surabowsurabow

つまりNginxをプロキシサーバとして使いつつ、PHP-FPMとソケット通信でPHPを実行するためにsocketを共有していた、というのが真相っぽい。

これを踏まえると、本番サーバでNginx(Webサーバ) + PHP-FPM(Appサーバ) の構成を取る場合、ソケット通信というのはできないかな?

ここで、NGINXがFCGIプロトコルを使ってリクエストをPHP FPMにproxyするように指示しなければなりません:

location ~ [^/]\.php(/|$) {
  ...
   fastcgi_pass 127.0.0.1:9000;

unixソケットを使っている場合は、fastcgi_pass を以下に変更してください:

fastcgi_pass unix:/var/run/php-fpm.sock;

PHP FastCGI の例 | NGINX

公式を見に行くと、間違いなさそう。
UNIXドメインソケットの場合はソケットファイルを指定する。
そうではなく、外部サーバに投げる場合の場合はIPアドレスを入力する(これがTCPのケースかな)

IPアドレス指定する例
nginxについてまとめ(Appサーバ編) - Qiita

surabowsurabow

完全に脇道だけれども、NginxとPHP-FPMが通信できんなら、PHPとMySQLが通信できてもおかしく無いよね?と思った。

そうしたらやっぱりできるらしい。
PHP: データベース接続 - Manual

更にMySQLクライアント自体がソケット通信を通じてMySQLサーバにアクセスしてるっぽい?
MySQLが起動しない(Can't connect to local MySQL server ~~)

はえ〜〜〜なるほどね〜〜今までソケットファイルが無いっていうのでMySQLが立ち上がらないことが度々あったけど内部的に使ってたからだったのね。
そして「なんでファイル作るだけで解決するんだ…?」と思ってたけど、ファイルに対する入出力で成り立つやりとりだからファイルさえあれば動くんやな。色々な知識が線で繋がった。

surabowsurabow

ここまでのことを踏まえると、本番に導入する場合には2つのサーバーを管理しないといけない、、ということになるかな。

でもそれ単純に大変そうですね…
あと、そもそもロードバランサ的な使い方をしようとしたときにAppサーバーを複数指定できないらしい。
だからNginx + Appサーバー の直結構成だとAppサーバーが1つしか立てられないらしい。
RailsとかだとUnicornっていう NginxとAppサーバーの間にもう1枚立てるとかで対応するケースもあるらしい。
nginxについてまとめ(Appサーバ編) - Qiita

…そんなんやるくらいなら普通にAWS ALB使ってEC2でApache使ってオートスケーリングまで組んだ方がよっぽど楽じゃね?
というどうしようもない結論に至りましたとさ。

surabowsurabow

理想はWebサーバとAppサーバは分けた方が良い、という話があるらしい。
理由は大量のリクエストを処理する際に、Appサーバはプログラムの実行に集中できるように、というところが大部分だと思う。
でも、それ以上に管理コストが嵩むとなると運用がツラくなりそうだしなぁ…

Rails開発におけるwebサーバーとアプリケーションサーバーの違い(翻訳) - Qiita

surabowsurabow

「AWS ALB」 VS 「NGINX Plus」最適なロードバランサー リバースプロキシの選択|NGINX エンジンエックス

と思っていたらロードバランサの比較を公式がやっていた。面白い。
この中で ALB<Nginx (Nginx Plus) としているポイントで気になるとこ

  • キャッシング:ALBではできないがNginxではできるとのこと。CloudFrontができるからマイナスじゃない
  • プロトコルのサポート:TCPとUDPがサポートされてるらしいけどHTTPSで十分なんだよな。あとUDP/TCP使いたければNLB使えば良い。
  • 移植性:AWSから滅多なことがない限り移植しないし、じゃあNginxだから移植が簡単かっていうと絶対そんなことは無い。
  • 証明書:アップストリームの証明っているのか?いらなくね?

そして圧倒的なメリットであるオートスケーリング的なことには一切触れてない。
単体では良いポイントあっても、複数のAWSリソース組み合わせたら圧倒的にALBの方が良い気がしてしまう。