PHPで常駐サーバーを動かす「Swoole」入門 ── なぜ速いのかを仕組みから理解する
この記事で伝えたいこと
「PHPは1リクエストごとに毎回ゼロから起動するから遅い」──長らくそう言われてきました。ところが Swoole という拡張を入れると、その前提そのものがひっくり返ります。Laravel の高速化ランタイム laravel/octane が Swoole を選択肢に採用したこともあり、PHP界隈でじわじわと存在感を増しています。
この記事では、Swooleが「何者なのか」「なぜ速いのか」を、従来のPHPの動き方と対比しながら整理します。ベンチマークの数字を並べるだけでなく、その数字が出る理由 に踏み込むことをゴールにします。
もくじ
- Swooleを一言でいうと
- 従来のPHPは何をしていたのか
- Swooleはその常識をどう変えるのか
- PHP-FPMとの違いを表で整理
- 最小構成のHTTPサーバーを書いてみる
- 速さの正体
- 向いている場面・注意点
- まとめ
Swooleを一言でいうと
Swooleは、PHPをCLI上で常駐させ、非同期・ノンブロッキングI/O・コルーチンで動かすためのC/C++製拡張 です。2012年に韓天峰(Rango)氏によって作られ、pecl などでインストールして使います。
ポイントは「フレームワーク」ではなく「PHPそのものの動き方を変える基盤」だという点です。開発者はepollやカーネルの知識を深追いしなくても、TCP・UDP・Unixソケット・HTTP・HTTP/2・WebSocketを扱う常駐サーバーをPHPだけで組めるようになります。設計思想としては Erlang・Node.js・Netty の考え方をPHPに持ち込んだもの、と説明されることが多いです。
なお、Swooleはカーネル機能に強く依存するため、動作環境は実質 Linux / macOS / WSL に限られます。Windowsでネイティブに動かすものではない、という点は最初に押さえておくとよいでしょう。
従来のPHPは何をしていたのか
Swooleのありがたみを理解するには、まず今までのPHP(PHP-FPM構成)の動きを思い出すのが近道です。
リクエストが来るたびに、PHPは概ね次のことを毎回繰り返します。
- スクリプトを読み込む
- コンパイルして実行する
- フレームワークやライブラリを初期化する
- レスポンスを返す
- すべて破棄して、次のリクエストのためにまっさらに戻す
この「毎回まっさらに戻す」設計は、状態が残らず安全でデバッグしやすいという大きな利点があります。一方で、リクエストのたびにブートストラップのコストを払い続けることになり、これが体感速度の足かせになっていました。
Swooleはその常識をどう変えるのか
Swooleは、上記の「毎回破棄」をやめます。プロセスを起動しっぱなしにして、フレームワークの初期化を最初の一度だけで済ませる のが根本的な発想です。
- アプリケーションのコードやオートローダをメモリに載せたまま常駐させる
- CPUコアごとにワーカープロセスを割り当て、マシンの並列性を使い切る
- I/O待ち(DBやAPIの応答待ち)はコルーチンで切り替え、その間に別のリクエストを処理する
Node.jsに近い常駐モデルですが、Swooleは コルーチン を使うため、Node.jsで悩まされがちな「コールバック地獄」に陥りにくいのが特徴です。見た目は同期コードのまま、裏側では非同期で動く、という書き味が得られます。
PHP-FPMとの違いを表で整理
| 観点 | PHP-FPM | Swoole |
|---|---|---|
| 実行モデル | リクエストごとに起動・破棄 | プロセスを常駐させ続ける |
| 初期化コスト | 毎リクエスト発生 | 起動時に一度だけ |
| 対応プロトコル | 主にHTTP | TCP / UDP / Unixソケット / HTTP / HTTP2 / WebSocket |
| I/O | 基本ブロッキング | epoll / kqueue によるノンブロッキング |
| 並列処理 | プロセス数に依存 | CPUコアごとにワーカーを配置+コルーチン |
| 永続接続 | 苦手 | WebSocketやTCP常駐に対応 |
| 状態保持 | 原則リクエスト間で共有しない | メモリ上で共有・管理できる |
表の最後の行、「メモリ上で状態を共有できる」は諸刃の剣です。速さの源泉であると同時に、リクエスト間でデータが漏れる/消えない という新しいバグの温床にもなります(後述)。
最小構成のHTTPサーバーを書いてみる
比較のために、同じ「Hello World」を3通りで書いてみます。
PHP-FPM(従来)
<?php
echo 'Hello world!';
Node.js
const http = require('http');
http.createServer((req, res) => {
res.end('Hello world!');
}).listen(8000);
Swoole
<?php
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$server = new Server('127.0.0.1', 9501);
$server->on('request', function (Request $request, Response $response) {
$response->end("Hello world!\n");
});
$server->start();
注目したいのは、Swooleのコードが echo で終わらず、$server->start() でプロセスを立ち上げて待ち受ける構造になっている点です。PHPのスクリプトというより、小さなアプリケーションサーバーを書いている感覚に近くなります。
速さの正体
ベンチマークで「Swoole > Node.js > PHP-FPM」という結果が出るのを目にすることがありますが、数字の絶対値は環境やチューニング次第で簡単に変わります。大事なのはなぜ速くなり得るのかで、理由は主に次の3つに集約できます。
- ブートストラップの省略:フレームワークの初期化を毎回やらないので、その分がまるごと浮く。
- ノンブロッキングI/O+コルーチン:DBやAPIの待ち時間に他のリクエストを処理でき、CPUを遊ばせない。
- コア全部を使い切る:ワーカーをCPUコアに割り当て、マルチコアを前提にスケールする。
逆にいえば、初期化が軽いアプリや、I/O待ちがほとんど発生しない処理では、差が縮まることもあります。「常に何倍速い」ではなく「初期化と待ち時間が重いほど効く」と理解しておくのが実務的です。
向いている場面・注意点
向いている場面
- WebSocketを使うチャットや通知など、常時接続が必要なリアルタイム系
- 外部API・DBへのI/Oが多く、待ち時間を並列化したいAPIサーバー
- 高頻度アクセスで、ブートストラップコストを削りたいエンドポイント
注意点
- プロセスが常駐するため、グローバル変数や静的プロパティに状態が残り続ける。従来の「リクエストごとにリセットされる」前提のコードはメモリリークや情報漏れの原因になりやすい。
- 常駐前提なので、コードを変更したら**ワーカーの再起動(リロード)**が必要。
- 動作環境がLinux系に限られる。
つまりSwooleは「入れれば勝手に速くなる魔法」ではなく、常駐サーバーとしての作法を理解して初めて活きる技術だといえます。
まとめ
Swooleの本質は、PHPを「リクエストごとに使い捨てる言語」から「常駐して動き続けるサーバー」へと組み替えることにあります。速さの正体は、初期化の省略・ノンブロッキングI/O・マルチコア活用という、ごく素直な仕組みの積み重ねです。
一方で、状態が残るモデルならではの落とし穴もあります。仕組みを理解したうえで使えば、PHPでもリアルタイム通信や高スループットなAPIを現実的な選択肢にできる──それがSwooleの面白さだと思います。まずは公式ドキュメントで、コルーチンやサーバーの各種オプションを触ってみるのがおすすめです。