frankenphp多个应用共用容器会出问题,因其多线程模型下所有应用共享进程地址空间,opcache、autoload、扩展等内存叠加导致rss远超memory_limit之和,易触发oom killer直接杀进程且无日志。

FrankenPHP 多个应用共用服务时,不能靠 memory_limit 分配资源——它只管单请求,不管总内存,超了直接被 OOM Killer 杀,连日志都不留。
为什么多个应用共用 FrankenPHP 容器会出问题
FrankenPHP 是多线程模型,所有 PHP 请求共享同一个进程的地址空间。哪怕你用不同域名跑 Laravel 和 WordPress,它们的 OPcache、autoload 类、静态缓存、扩展初始化数据全挤在一块内存里。你给每个应用单独设 memory_limit = 256M,不代表总共只用 512MB——实际 RSS 内存可能轻松突破 1.2GB(尤其开了 Mercure 或大量并发时)。
常见错误现象包括:
- 容器随机退出,
dmesg | grep -i "killed process"显示 FrankenPHP 被 OOM Killer 杀掉 - 健康检查失败但无 PHP 错误日志,
ps aux --sort=-rss发现 FrankenPHP 进程 RSS 持续 >90% 容器限制 - OPcache 频繁重编译(
opcache_get_status()['oom_restarts'] > 0),说明 OPcache 自身内存不足,反向推高整体内存抖动
必须分三层设限:PHP 层 + 容器层 + 应用隔离层
光改 php.ini 不顶用。得同步控制三处:
-
memory_limit设为单请求安全上限(如256M),且确保所有应用入口(index.php、.frankenphp.router.php)不调用ini_set('memory_limit', '-1') - Docker 中用
mem_limit硬性封顶(例如1.5g),并设mem_reservation: 768m防冷启动抖动 - 每个应用独立部署为子目录或子域名,并在
.frankenphp.router.php中显式加载对应环境配置(如$_ENV['APP_ENV'] = 'prod-laravel'),避免框架自动加载冗余模块
注意:opcache.memory_consumption 必须统一配置(比如 128),不能让 Laravel 用 256M、WordPress 用 64M——OPcache 是进程级共享的,混用会导致缓存污染和提前淘汰。
怎么估算真实内存需求
别信 memory_limit × 并发数 这种算法。实测中更靠谱的是:
- 单应用冷启动后,用
ps -o rss= -p $(pgrep -f frankenphp)查 RSS 基线(通常 80–120MB) - 加压测试(如
hey -n 100 -c 10 http://localhost/healthz),观察 RSS 峰值增幅,取 3 倍标准差作为缓冲 - 多个应用叠加时,按「基线 + max(各应用峰值增幅) + 20% 共享开销」估算,例如 Laravel 基线 100MB / 峰值+180MB,WordPress 基线 90MB / 峰值+120MB → 建议容器
mem_limit = 1g起步
如果用 Caddy 的 reverse_proxy 把多个 FrankenPHP 实例反代到同一域名下,反而更可控——每个实例独占内存,OOM 只影响局部,且能分别调优 num_threads 和 OPcache。
容易被忽略的泄漏点:上传临时文件和长连接
FrankenPHP 默认把小上传()全放内存,多个应用同时上传就会吃垮 RSS。务必在全局 <code>php.ini 中显式设:
upload_max_filesize = 8M post_max_size = 10M max_memory_upload = 4M
另外,Worker 模式下常驻的 Guzzle HTTP 客户端、PDO 连接池、Mercure 订阅句柄若没手动释放,会在 Goroutine 生命周期内持续累积。这类泄漏不会触发 memory_limit 报错,但会让 RSS 每小时涨 50MB+——得靠 process-exporter 监控 RSS 趋势,而不是只看 PHP 的 memory_get_usage()。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











