Nginx Unit で Laravelを動かしてみた

f:id:hanhan1978:20170914162426p:plain

こんにちはエンジニアの @hanhan1978 です。2017年9月6日にNginxがApplication Platformの「Unit」をリリースしました。 Introducing the NGINX Application Platform with Controller and Unit

世界中がザワザワしているようですが、特に日本はザワザワしているようで、Google Trendで調べて見たら日本が一番バズってます。 Nginx Unit - Google トレンド

PHP界隈でも、PHP-FPMに取って代わる&HTTPで通信できるモダンなアプリケーションサーバがついに登場か!?ということでザワザワしています。 自分も、Dockerコンテナ上でPHPアプリケーションを動かす最適解を勝手に探し求めている人間なので、もしかして「Unit」はPHPアプリケーションのコンテナ化を促す強い推進力になるかもとウキウキしてしまいました。

というわけで、「Unit」でひとまずLaravelのアプリケーションを動かしてみて、どんな構成で動かせばいいのか調べてみました。

UnitでLaravel動かす時の構成

サーバ構成図

f:id:hanhan1978:20170914154632j:plain:w500

Nginxを前段に配置して、*.phpのリクエストをReverse ProxyでUnitに振り分ける構成です。

※Ubuntu 16.04 (Xenial) を使って、Vagrant上に環境構築しました。

ハマったところ&分かったところ

1. アプリケーションサーバに対する誤解

完全に先入観による誤解だったのですが、Apache(mod_php)とか Tomcatみたいなイメージをしていました。つまりLaravelのアプリケーションを DocumentRootにおいてあげれば、静的ファイルも含めてよしなに処理してくれるだろうと思ったのですが、Unitが処理するのはPHPだけです。

イメージ的には、PHP-FPMと同様です。Unitの前段に静的ファイルを処理するWebサーバを配置する必要があります。今回の構成ではNginxを使いましたが、別にApacheでも何でも良いです。

2. PHPのextensionについて

Ubuntu版のUnitは、パッケージ管理ツールでインストールした libphpを利用しているようです。そのため、 apt-get install php7.0-mysql とかしてextをインストールしてUnit再起動すれば、追加のextも普通に使えるようになりました。

個別にPHPをソースインストールしているような環境では、適切にヘッダファイル指定してUnitを再コンパイルする必要がありそうです。 この辺、どうやってPHPを実行しているのかとかは、もう少し詳細に調査したいところです。

3. Proxyの設定

FastCGIの時と違って、Reverse Proxyで処理を飛ばすので、ヘッダの情報を適切に引き継いで上げないとLaravel側がRoutingの判断をできません。 Laravelの場合は、X-Original-UrlRequest URIを渡してあげないと、全部 / へのアクセスになってしまいます。

  location ~ \.php$ {
    try_files $uri /index.php =404;
    proxy_pass http://unit_backend;
    proxy_set_header X-Original-Url $request_uri;
    proxy_set_header Host $host;
  }

認証でAuth Headerとか使う場合も Proxyの設定周りで引き継いで上げる必要があります。 この辺は、そもそもProxy使って構成を作ってる他言語界隈の情報や知見が使えるかと思います。

いきなりPHP-FPMからUnitに切り替えると、少しハマるかもしれません。

パフォーマンス測定してみた。

Nginx with PHP-FPM の場合と Nginx with Unit の構成で、パフォーマンス比較をやってみました。

構成 リクエスト数/30sec
Nginx with PHP-FPM 4202
Nginx with Unit 2921

いずれも siegeで並列度150のリクエストで最も多くのリクエストを処理しましたが、軍配はPHP-FPMに上がりました。 Unitは、workerを増やしてもこれ以上は性能が引き出せず。

まだまだ、パフォーマンス面では改善の余地がありそうです。

※余談ですが、並列度を高めていった時に、PHP-FPMだと少しずつエラー率が上がったのですが、Unitは一気に崩れるような傾向がありました。

コンテナ作成者目線で考えると

現状のPHPアプリケーションに対してはPHP-FPMの置き換え候補という感じがしました。

DockerでPHPアプリのコンテナを作っている人は、Apache(mod_php)のコンテナにするか、NginxとPHP-FPM(複数プロセス)を同居させるコンテナを作ることが多いのですが、Unitも単体で静的ファイルを処理できるわけではないので、 Nginx + Unit という構成でコンテナを作ることになりそうです。

UnitだけでPHPアプリを良しなに処理できるかも最高〜とか勝手に妄想してましたが、そうはなりませんでした。残念。

まとめ

まだVersion 0.1 ということなので、まだまだこれからというアプリケーションサーバですが、多数の言語を動作させられたり、設定内容をcurlでAPIに直接食べさせたりするところに未来感を感じて、すごく楽しかったです。

まだ、POSTが出来なかったりとか、色々と不具合ありそうですが、HTTPで通信出来るPHPのアプリケーションサーバというのは、PHPerも待望していたものだと思いますので、応援していきたいと思います!

おまけ

UnitインストールのAnsible Playbook(For Ubuntu)抜粋

- name: install apt keys
  apt_key: url=http://nginx.org/keys/nginx_signing.key state=present

- name: set repository
  apt_repository: repo='deb http://nginx.org/packages/mainline/ubuntu/ xenial nginx' state=present

- name: set repository
  apt_repository: repo='deb-src http://nginx.org/packages/mainline/ubuntu/ xenial nginx' state=present

- name: apt update
  apt: update_cache=yes

- name: install nginx unit
  apt: name={{item}}
  with_items:
     - unit

- name: ensure nginx unit start
  service: name=unitd state=restarted enabled=yes

Ansible使う方は、参考にどうぞ。UnitのReadMeに書いてある手順をPlaybookにしただけですが。