「WordPress は Cloudflare で動くか」という質問には、これまで「動かない」と答えるのが普通でした。Workers が実行できるのは JavaScript と WebAssembly で、WordPress には PHP と MySQL が要るからです。静的ファイルに書き出すか、サーバーを残すかの二択でした。
いまはこの答えが変わっています。WordPress Playground プロジェクトが PHP を WebAssembly 向けにビルドしていて(php-wasm)、そのビルドは Worker の中でも動きます。
私たちは、これを使って既存の WordPress サイトを Workers に移すオープンソースのツール HostlessWP(GPL-2.0)をメンテナンスしています。npx hostlesswp を実行すると、wp-config.php を読み取り、WordPress 本体・テーマ・プラグインを php-wasm(PHP 8.3)で動かし、既存の MySQL には Hyperdrive 経由で接続し、メディアライブラリは R2 などの S3 互換ストレージに置きます。以下は、実用になるかどうかを左右したポイントと、実際に測った数字です。
1. いちばん効くのは Worker を置く場所
WordPress はクエリを一つずつ順番に発行します。今回のテストでは、コアのトップページで 29 回、WooCommerce のトップページで 74 回でした。そのたびにデータベースまでの往復を待つことになります。
データベースは米国東部(バージニア)、リクエストはシンガポールから Cloudflare に入る条件で測りました。デフォルトの配置では Worker が訪問者の近くで動くので、クエリのたびに太平洋を往復します。
| 構成 | 1 クエリ | コアのトップページ | WooCommerce のトップページ |
|---|---|---|---|
| 訪問者の近く(シンガポール)で実行 | 約 230 ms | 7.7 秒 | 19.6 秒 |
データベースの隣で実行(placement.region = "aws:us-east-1") |
約 33 ms | 1.2〜1.3 秒 | 2.9〜3.2 秒 |
| データベースの隣で、Hyperdrive を使わず直接 TCP 接続(未リリース) | 約 2 ms | 0.07 秒 | 0.19 秒 |
ウォーム状態のリクエストで、データベースの待ち時間を含む PHP の処理時間です。各セルは 1〜5 サンプルの中央値なので、桁の目安として読んでください。Worker をデータベースの隣に固定するとページは約 6 倍速くなりました。そのため HostlessWP はデータベースの場所を調べて placement.region を自動で設定します。
ログインしていない訪問者には Workers KV のページキャッシュから返すので、PHP もデータベースも動きません。上の数字が効いてくるのは、ログインユーザー、管理画面、キャッシュされないページです。
2. Hyperdrive は 1 クエリあたり約 30 ms 増え、セッションを保持しない
同じ Worker の呼び出しの中で、直接接続の SELECT 1 は約 2 ms、接続の確立は 2〜7 ms でした。Hyperdrive 経由では約 33 ms です。その差のうち、どこまでが Hyperdrive のプールまでの距離で、どこまでが処理そのものなのかは切り分けられていません。直接接続をまだリリースしていないのは、テスト用データベースがプライベート CA の証明書を使っていて、Workers の TLS クライアントが受け付けなかったためです。
見落としやすいのは、Hyperdrive が連続するステートメントを別々のサーバー接続で実行しうる点です。WordPress やプラグインが SET で設定したセッション変数は、次のクエリでは消えているかもしれません。私たちは SET_VAR ヒントでステートメントごとに状態を渡し、SELECT @@var には SHOW VARIABLES の結果で答え、SQL_CALC_FOUND_ROWS のページングは COUNT を並列に実行する形に変えました。この最後の変更で、REST API の投稿一覧は約 2.5 秒から 1.6 秒になりました。
3. 計算中は時計が進まない
Workers では CPU 処理の間、時計が止まります。時刻が変わるまでループする PHP のコード(たとえば uniqid())は終わらなくなります。読み出すたびに必ず少し先の時刻を返す、単調増加の時計にすることで解決しました。
4. php-wasm の OPcache は明示的に有効にしないと動かない
php-wasm の SAPI は OPcache のホワイトリストに入っていないため、デフォルトでは OPcache が起動しません。これをパッチで有効にし、共有メモリに置き、事前コンパイルしたスクリプトをマウントすると、WordPress と WooCommerce くらいの規模のコードでは大きな差が出ます。
5. まだできないこと
- PHP の
mail()。HTTP API で送信するメールプラグインを使ってください。 - 管理画面からのプラグインのインストールや更新。元のサイトで変更してから再デプロイします。
- マルチサイト。
- Redis などのオブジェクトキャッシュのドロップインは除外されます(WordPress 標準のキャッシュを使います)。
- Imagick。画像処理は GD で行います。
- データベースの隣に配置すると、コールドスタートが増えました(連続 25 リクエスト中 11〜16 回。デフォルト配置では 0 回)。原因はまだわかっていません。
WordPress.org でインストール数の多い上位 30 プラグインはページ単位で読み込みと動作を確認し、WooCommerce のチェックアウト、Elementor のエディタ、Yoast のサイトマップはエンドツーエンドでテストしました。プラグインごとの結果は互換性一覧にあります。
試すには
npx hostlesswp check # 読み取りのみの互換性レポート。何も変更しません
npx hostlesswp # 対話式のセットアップとデプロイ
今のサイトには手を加えないので、ドメインを切り替えるまでは今まで通り配信されます。この方式で動いている WooCommerce の公開デモがあります: https://hostlesswp-demo.qc2uyes.workers.dev (demo / demo でログイン、3 時間ごとにリセット)。測定方法と数字の詳細: https://hostlesswp.com/benchmarks
まだ初期プレビュー(v0.1)です。ご自身のサイトで試したら、ぜひ数字を教えてください。