send_buffer_limit是workerman中tcpconnection的发送缓冲区软上限,仅暂停超限连接的send操作,不阻止php内存中数据累积,故无法防止oom。

send_buffer_limit 是什么,为什么它不解决内存溢出?
send_buffer_limit 是 Workerman 中 TcpConnection 对象的一个属性,表示该连接发送缓冲区的**软上限**(单位字节),默认值为 1024 * 1024 * 2(2MB)。但它**不是内存保护开关**——设了它,Workerman 不会主动拒绝数据、也不会提前断连;它只在每次调用 $connection->send() 后检查已缓存但尚未发出的数据量,若超限,就暂停该连接的后续 send,直到已有数据被系统 TCP 栈消费掉、缓冲区回落到阈值以下。
换句话说:send_buffer_limit 控制的是「发得慢一点」,不是「别让内存涨上去」。如果你的业务持续往一个卡住的连接狂塞大文件或高频消息,缓冲区会先顶到这个值,然后阻塞,但此时 PHP 用户态内存里已经存了大量待发送数据(比如 file_get_contents() 加载的整个文件),OOM 风险仍在。
真正导致 send 相关内存溢出的三个常见原因
- 用
file_get_contents($path)+$connection->send()发大文件:整份文件加载进 PHP 内存,再拷贝进连接发送缓冲区,双份占用 - 客户端接收极慢或断连未及时检测(
onClose未触发),而服务端仍不断send():数据越积越多,send_buffer_limit只是延缓崩溃,不阻止累积 - 批量广播时未做流控,10 万连接每人都 send 10KB,瞬间压爆内存:即使每个连接都低于
send_buffer_limit,总内存占用仍可能达 GB 级
怎么配 send_buffer_limit 才算合理?
配它不是为了防 OOM,而是为了给系统留出反应窗口。建议按连接平均带宽和网络 RTT 估算:
- 对普通 WebSocket 聊天,设
1024 * 64(64KB)足够:消息小、交互快,缓冲区无需太大 - 对文件传输类服务,可设
1024 * 1024 * 4(4MB),但必须配合onBufferFull回调做降级 - 永远不要设为
0或负数——这会让 Workerman 忽略该限制,失去最后的缓冲区水位提示 - 必须在连接建立后、首次 send 前设置,例如在
onConnect里:$connection->send_buffer_limit = 1024 * 1024 * 4;
注意:send_buffer_limit 是 per-connection 的,不能全局统一配置;Worker 进程启动时无法预设,只能靠业务逻辑动态赋值。
比配 send_buffer_limit 更关键的三件事
单靠这个参数根本挡不住内存爆炸。真正要做的:
- 发文件改用
$connection->sendfile($filepath):内核零拷贝,完全绕过 PHP 用户内存,不占memory_get_usage() - 所有
send()调用前加判断:if (!$connection->isClosed() && $connection->getSendBufferSize() ,避免往已卡死的连接硬塞 - 监听
onBufferFull并主动干预:$connection->onBufferFull = function ($connection) {<br> // 例:暂停该连接的消息推送,或记录告警<br> $connection->pause();<br>};
最容易被忽略的是:send_buffer_limit 触发后,Workerman 不会自动清理已缓存数据,也不会释放连接——你得自己决定是 pause()、close(),还是切到备用通道。没这层响应逻辑,配再大的值也只是把崩溃时间推迟几秒而已。











