PHP不适合长连接实时推送,应采用PHP触发通知+独立WebSocket服务推送的架构。PHP负责业务逻辑和发送REST请求,由Swoole、Node.js或Go等处理连接维持与广播,客户端用原生WebSocket监听消息。

PHP 本身不擅长长连接和实时推送,直接用 PHP-FPM + 普通 HTTP 请求做“实时通知”必然卡顿、超时或漏发——这不是配置问题,是模型限制。
为什么不能只靠 sleep() + flush() 实现真实时
这种方案常被称作“长轮询模拟”,但实际中极易失败:
-
max_execution_time和nginx proxy_read_timeout多层超时叠加,连接常在 30–60 秒内被强制断开 - 每次通知需重建 HTTP 连接,客户端频繁重连导致延迟毛刺明显(尤其移动端)
-
ob_flush()+flush()在 FastCGI 环境下经常无效,Nginx 默认启用fastcgi_buffering on,会攒满 4KB 才发包 - 并发高时 PHP 进程被长连接占满,新请求排队,整个站点变慢
推荐架构:PHP 做通知触发 + 独立服务做推送
让 PHP 回归它最擅长的事:处理业务逻辑、生成通知数据;把连接维持、广播、心跳交给更合适的组件。
典型组合:
立即学习“PHP免费学习笔记(深入)”;
-
触发端(PHP):调用
file_get_contents()或cURL向推送服务的 REST API 发送通知(如POST /api/notify),传user_id、message、type -
推送服务(非 PHP):用
WebSocket服务器,例如Swoole(PHP 写但脱离 FPM)、Node.js(ws或Socket.IO)、Go(gorilla/websocket) -
客户端(JS):用原生
WebSocket连接,监听onmessage,收到后调用本地提示逻辑(NotificationAPI 或 DOM 更新)
示例(PHP 触发):
$data = json_encode(['user_id' => 123, 'msg' => '你有一条新消息']);
$opts = ['http' => ['method' => 'POST', 'header' => "Content-type: application/json", 'content' => $data]];
file_get_contents('http://localhost:8080/api/notify', false, stream_context_create($opts));
如果必须纯 PHP 实现(低并发内网场景)
仅限测试或极小规模(
- PHP 脚本开头加:
set_time_limit(0)、ignore_user_abort(true)、ob_end_flush()、ini_set('output_buffering', 'off') - Nginx 配置中禁用缓冲:
fastcgi_buffering off,并调大超时:fastcgi_read_timeout 300 - 客户端 JS 必须实现自动重连逻辑,因为连接中断无法避免
- 不要用
while(true)查数据库轮询,改用pcntl_signal()+pcntl_sigwaitinfo()接收信号,由另一个进程(如队列消费者)发信号唤醒
真正稳定的实时通知,核心不在“PHP 怎么写”,而在“谁来管连接”。一旦用户量过百、通知频率过秒级,就必须把状态维持移出 PHP-FPM 生命周期——这点容易被忽略,直到压测时大量 504 和重复通知出现才意识到。



















