[PHP]Golang製PHPアプリケーションサーバRoadRunnerを試す
こんにちは、ナカエです。
本日はGo言語で書かれたPHPアプリケーションサーバ、RoadRunnerについての記事です。
PHPアプリケーションサーバの新潮流
昨今のPHP界隈では、Swooleに代表されるように、よくあるApache+mod_phpやPHP-FPMによる従来の構成と異なる実行方法を持つPHPのためのHTTPサーバまたはアプリケーションサーバが少しずつ注目を集めるようになってきました。
従来のPHPの実行方式における「1つのリクエストごとにアプリケーションの初期化が行われレスポンスを返すと状態がリセットされる」という前提を覆し、アプリケーションの初期化の前倒しによる大幅なパフォーマンスの向上を図れると話題を呼んでいます。
RoadRunner
RoadRunnerもそんな新興のアプリケーションサーバの1つで、Go言語で書かれています。 HTTPのリクエストを前段のGoのHTTPハンドラがさばき、ロードバランサ/プロセスマネージャがPHPのWorkerにリクエストを割り振るという構成になっています。
開発元のSpiral Scoutのブログ記事 PHP was never meant to die によると、彼らは開発スタックにGolangを導入してその力を実感し、Golangの力を借りて既存のPHPのアプリを強化できないだろうかと考えたのが開発のきっかけだったようです。 上記記事は2013年に書かれたPHP is meant to dieという記事へのアンサー記事にもなっており、熱意溢れるとても良い話でした。
通常のHTTPサーバだけでなく、RoadRunnerによるgRPCサーバの実装も公開されており、PHPの新しい可能性を見せてくれます。
RoadRunnerを試す
RoadRunnerを動かすには、ビルド済みのバイナリをDLするか、Golangを使ってビルドする必要があります。 今回はホストマシンの環境を汚したくないため、Docker環境を構築しました。
Dockerfile
FROM php:7.2-cli
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
git \
vim \
zlib1g-dev \
unzip
# Install Go
RUN wget -O - https://dl.google.com/go/go1.11.4.linux-amd64.tar.gz | tar -C /usr/local -xzf -
ENV PATH $PATH:/usr/local/go/bin
ENV GO111MODULE on
# Install RoadRunner
WORKDIR /go/src
RUN git clone --depth 1 https://github.com/spiral/roadrunner \
&& cd /go/src/roadrunner \
&& make \
&& make install
COPY ./.rr.yaml /etc/roadrunner/.rr.yaml
# Install PHP Extensions
RUN docker-php-ext-install zip \
&& docker-php-ext-install opcache \
&& docker-php-ext-enable opcache
# Install Composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === rtrim(file_get_contents('https://composer.github.io/installer.sig'))) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer
WORKDIR /var/www
ENTRYPOINT ["/usr/local/bin/rr", "serve", "-c", "/etc/roadrunner/.rr.yaml"]
PHP用のイメージを元にしていますが、RoadRunnerのビルドのためにGo1.11も入れています。
下記Gitリポジトリをクローンすればdocker-composeにより手軽に環境を立ち上げることができます。
n1215/roadrunner-docker-skeleton
PHPの処理の書き方
RoadrRunnerの設定ファイルでPHPのWorkerのエントリポイントとなるファイルが指定されており、
http:
address: :8080
workers:
command: "php /var/www/app/psr-worker.php"
pool:
numWorkers: 4
そのファイル内にPSR-7のリクエストを受け取ってPSR-7のレスポンスを返す処理を記述するのが基本となります。
<?php
declare(strict_types=1);
ini_set('display_errors', 'stderr');
include 'vendor/autoload.php';
$relay = new Spiral\Goridge\StreamRelay(STDIN, STDOUT);
$psr7 = new Spiral\RoadRunner\PSR7Client(new Spiral\RoadRunner\Worker($relay));
while ($req = $psr7->acceptRequest()) {
try {
$resp = new \Zend\Diactoros\Response();
$resp->getBody()->write('Hello, world!');
$psr7->respond($resp);
} catch (\Throwable $e) {
$psr7->getWorker()->error((string)$e);
}
}
既存のフレームワークとの統合
PSR-7のリクエストからレスポンスを返せれば処理の実体は何でも良く、既存のフレームワークを組み合わせることももちろん可能です。
RoadRunnerのWikiにはPSR-7-Bridgeを利用したLaravelやSymfonyとの統合例が掲載されています。
Laravelでnginx+PHP-FPMの構成とパフォーマンスを比較した記事 用 RoadRunner 加速 Laravel 应用(注: 中国語)によると、LaravelのHome画面で30倍ものトランザクションを叩き出しています。
まとめ
今回は新進気鋭のアプリケーションサーバ、RoadRunnerを試すためのDocker環境を構築しました。 個人的に、SwooleやRoadRunnerが見せてくれるPHPの新たな可能性に大いに期待しています。今後も調査を継続していく予定です。