Broken Pipe 是 TCP 连接被对方或中间设备主动关闭后本地仍写数据导致的系统级错误,需用 tcpdump 抓包确认 FIN/ACK 发起方,而非直接重启。

看到 Broken Pipe 别急着重启,先抓包看谁先断的连接
这是 Swoole 对外发起 HTTP 请求(比如调用支付回调、第三方 API)时最典型的网络异常之一,错误栈里常带 Broken pipe 或 Connection reset by peer。它不是 PHP 报错,而是底层 TCP 连接被对方或中间设备主动关闭后,你这边还试图往已失效的 socket 写数据导致的系统级错误。
- 先确认是不是对方关的:用
tcpdump抓握手和 FIN 包,命令如tcpdump -nni any 'tcp port 8080 and host api.example.com' -w out.cap,重点看 FIN/ACK 是谁先发的 - 别在代码里 catch
Broken Pipe——它属于EPIPE系统错误,PHP 默认不抛异常;要用set_error_handler捕获并转成异常,否则静默失败 - 常见诱因:对方服务超时强制断连、Nginx 的
proxy_read_timeout设得太短、CDN 中间层主动回收空闲连接
ps -ef | grep swoole 找不到 master 进程?可能早就崩了没拉起
更新后系统工具报“网络错误”,表面是连不上,实则常是 Swoole 主进程已退出,但 Worker 还在苟延残喘,或者 systemd 服务没配自动重启。
- 执行
ps -ef | grep swoole前,先跑systemctl status your-swoole-service,看是否显示inactive (dead)或failed - 如果
ps真没结果,别直接重试启动脚本——先查日志:journalctl -u your-swoole-service -n 50 -f,重点看WorkerExit后有没有Segmentation fault或 OOM killer 日志 - 注意宝塔后台的“Swoole 服务管理”按钮只是个 shell 封装,它执行的启动命令可能没加载你的环境变量(比如
LD_LIBRARY_PATH),导致swoole.so加载失败静默退出
回调收不到完整数据?不是网络问题,是 Stream 被协程调度截断了
yansongda/pay 在 Swoole 下收支付回调经常 $result 长度远小于预期(比如 strlen($result) ),这不是丢包,是协程环境下 <code>php://input 流读取被并发请求抢占或缓冲区未刷出。
- 不要依赖
file_get_contents('php://input')——Swoole 的协程 HTTP Server 不保证该流一次性可读完,尤其当客户端分块发送时 - 改用
$request->rawContent()直接取原始请求体,它是 Swoole 内部已拼好的完整二进制数据 - 若必须用流,加
stream_set_blocking($fp, true)和stream_get_contents($fp),但性能差且仍可能被协程切换打断 - 配置项
http_compression开启时也会干扰原始流长度,调试阶段建议关掉
max_request 设太高,内存泄漏会拖垮整个 Worker
线上 Swoole 服务偶发性卡顿、响应变慢、WorkerError 频发,往往不是网络抖动,而是单个 Worker 处理太多请求后内存持续增长,最终触发 GC 停顿或 OOM。
-
max_request不是越高越好:设成10000看似稳妥,但如果每个请求都 new 一个没 unset 的大对象,10000 次后内存就飙到几百 MB - 用
memory_get_usage(true)在WorkerStart和WorkerExit打点,对比差值;再结合top -p $(pgrep -f 'swoole')看 RSS 是否持续上涨 - 真正稳定的值得压测定:从
500起步,观察 24 小时内存曲线,逐步放宽;别迷信文档里的“推荐值”
网络层的问题,最后往往要落到进程生命周期和内存行为上验证。别只盯着 ping 和 curl,ps、journalctl、tcpdump 这三个命令才是 Swoole 故障现场的铁三角。










