FrankenPHP核心优势是零依赖安装,仅需下载对应平台二进制并赋权即可运行;RoadRunner则必须同时满足rr二进制可用和PHP启用sockets扩展两个硬性条件,且配置、启动与调试方式均与FrankenPHP完全不同。

FrankenPHP 安装只要一个二进制,RoadRunner 需要额外 PHP 扩展和 rr 二进制
FrankenPHP 的核心优势是“零依赖安装”:下载对应平台的 frankenphp 二进制(Linux/macOS/Windows),加执行权限,就能直接跑 php 文件或 Laravel 项目。它不依赖 sockets 扩展,也不需要提前编译或安装任何 PHP 模块。
RoadRunner 则必须满足两个硬条件:
-
rr二进制得单独下载或通过 Docker 获取(比如ghcr.io/roadrunner-server/roadrunner:2025.1.15) - PHP 必须启用
sockets扩展(docker-php-ext-install sockets),否则 worker 启动失败,报错Class 'React\Socket\TcpServer' not found或直接卡在waiting for workers - 若用 Laravel Octane,还得确保
opcache已启用——RoadRunner 依赖 opcache 缓存预编译的类,否则每次请求都重加载,性能反降
配置文件结构差异大:FrankenPHP 用 Caddyfile,RoadRunner 用 .rr.yaml
FrankenPHP 的配置本质是 Caddy 的配置,写法熟悉、语义清晰。静态资源、TLS、路由规则全在一个 Caddyfile 里,比如:
localhost root * /var/www/public php_server
而 RoadRunner 的 .rr.yaml 是纯服务调度配置,不处理 HTTPS 或静态文件,只管 worker 生命周期、内存限制、超时等。常见坑点:
立即学习“PHP免费学习笔记(深入)”;
-
http.address写成localhost:8080而不是0.0.0.0:8080,导致容器外无法访问 -
pool.num_workers设太高,PHP 进程吃光内存,触发 OOM kill - 没配
reset_mode: http,worker 处理完请求后不自动重置全局状态,$_SESSION 或 static 变量残留,引发并发数据污染
Laravel Octane 下启动命令完全不同
两者虽都支持 Laravel Octane,但初始化和运行路径不互通:
- FrankenPHP:执行
php artisan octane:install --server=frankenphp,会自动生成frankenphp-worker.php和基础Caddyfile,之后直接php artisan octane:start即可 - RoadRunner:需先确保
rr在$PATH,再运行php artisan octane:install --server=roadrunner,生成的是.rr.yaml;启动时实际调用的是rr serve,不是 PHP 命令 - 如果混用——比如用
rr serve去跑 FrankenPHP 生成的 worker 文件,会报错Unknown worker type "frankenphp"
进程模型和调试方式根本不同
FrankenPHP 是单进程模型:Caddy + PHP 运行时在同一个 Go 进程里,日志统一输出到 stdout,strace 或 gdb 调试对象是 frankenphp 本身;HTTP/3、自动 TLS 等能力开箱即用,无需额外配置。
RoadRunner 是双进程模型:Go 主进程(rr)监听请求,PHP worker 进程通过 Unix socket 或 TCP 与之通信。这意味着:
- 出问题时要分两头查:主进程 log(
rr输出)和 worker log(PHP 的error_log或var/log/rr.log) - PHP worker 崩溃不会导致整个服务挂掉,但
rr主进程挂了,所有 worker 都失效 - 想看 PHP worker 实际内存占用?得用
ps aux | grep php单独过滤,不能只看rr进程 RSS
最常被忽略的一点:FrankenPHP 的 worker 模式默认复用整个 PHP 运行时(包括 OPcache、已加载扩展),而 RoadRunner 的 worker 默认只复用 autoloader 和框架引导逻辑——如果你在 bootstrap/app.php 里写了 new PDO(...),FrankenPHP 会把它变成全局连接池的一部分,RoadRunner 则不会,除非你显式用 PDO::ATTR_PERSISTENT 或连接池中间件。



















