Apache+SSE+PHP环境下SSE正常但其他请求长期Pending问题求助
解决SSE导致其他请求Pending的问题
兄弟,这个坑我之前踩过!核心原因是SSE的长连接特性和PHP/Apache的会话锁、进程管理机制冲突了,给你几个针对性的解决思路:
1. 立刻释放PHP会话锁(最关键!)
PHP的Session默认是文件存储,而且请求期间会加独占锁——如果你的SSE请求开启了Session(比如要获取用户登录状态),那其他所有需要Session的请求都会被死死堵住,直到SSE连接断开。
解决办法很简单:在SSE控制器里,拿到需要的Session数据后,马上调用session_write_close()释放锁:
session_start(); // 只在这里获取你需要的Session数据,比如用户ID $user_id = $_SESSION['user_id'] ?? 0; // 立刻关闭Session,释放锁! session_write_close(); // 接下来才是SSE的响应头和推送逻辑 header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); while (true) { // 推送消息的逻辑 echo "data: " . json_encode(['msg' => '新消息']) . "\n\n"; // 强制输出缓冲区内容 ob_flush(); flush(); // 避免太频繁推送,适当休眠 sleep(1); // 检查客户端是否断开连接,及时退出循环 if (connection_aborted()) { break; } }
2. 调整Apache MPM配置(针对Prefork模式)
如果你的Apache用的是Prefork MPM(默认模式),每个HTTP连接会占用一个独立进程,SSE的长连接会一直占着这个进程不释放——当进程池被耗尽时,新的请求就只能处于Pending状态。
你之前改了没效果可能是参数没到位,试试这些调整:
- 把
MaxRequestWorkers(旧版本叫MaxClients)调大,比如根据服务器配置设为200-500; - 如果服务器支持,直接换成Event MPM(异步处理模式),它能高效处理大量长连接,不会像Prefork那样被SSE拖垮;
KeepAliveTimeout不要设太长(比如5秒),但这个对SSE本身影响不大,重点还是进程数和Session锁。
3. 确保输出缓冲彻底关闭
PHP的输出缓冲会把推送的内容攒着不发,导致SSE连接一直挂着,也可能间接加重进程占用。确保:
- 在php.ini里把
output_buffering设为Off; - 在SSE代码开头加上
ob_end_flush()关闭默认缓冲,每次推送后必须调用ob_flush()和flush()强制输出。
4. 进阶方案:用Nginx反向代理或专门的SSE服务
Apache+PHP的组合天生不擅长处理大量长连接,如果你的聊天场景用户量较大,建议:
- 用Nginx做反向代理,让Nginx处理SSE的长连接,PHP只负责生成推送数据;
- 或者直接用Node.js/Go这类更适合长连接的语言来单独处理SSE服务,PHP作为后端接口提供数据。
内容的提问来源于stack exchange,提问作者Sergey Shirnin
相关产品推荐
相关产品推荐

