workerman静默丢连接是因内核全连接队列满后丢弃ack包且不发rst,故netstat无异常;实际生效队列长度为min(应用层backlog, net.core.somaxconn),而workerman默认使用系统默认backlog(常为128),需同步调优tcp_max_syn_backlog、file-max、tcp_tw_reuse等参数并验证ss -lnt的send-q与listenoverflows计数。

为什么 Workerman 会静默丢连接,而 netstat 看不出异常?
Workerman 是单线程 accept(主线程调用 accept()),当并发建连速度超过它处理能力时,已完成三次握手的连接会堆积在内核的「全连接队列」里。这个队列满后,内核直接丢弃新 ACK 包,不发 RST,也不记日志——所以 netstat -s 可能没报错,但 ss -lnt 的 Recv-Q 持续接近 Send-Q,或 netstat -s | grep -i "listen overflows" 显示非零计数,就是典型信号。
net.core.somaxconn 和 Workerman 实际生效的 backlog 是什么关系?
Workerman 底层调用 socket.listen() 时,若未显式传入 backlog 值,会取系统默认值(常为 128),而该值受 net.core.somaxconn 全局限制。最终生效队列长度是:min(应用层传入的 backlog, net.core.somaxconn)。也就是说,即使你把 net.core.somaxconn 调到 65535,Workerman 还是用默认 128,那实际队列仍是 128。
- Workerman 本身不提供配置项暴露 backlog,依赖底层 PHP socket 行为
- PHP 7.4+ 默认使用
SOMAXCONN系统值,但旧版 glibc 或容器环境可能仍卡在 128 - 验证方式:启动 Workerman 后执行
ss -lnt | grep :端口号,看Send-Q列是否达到预期(如 65535)
只改 somaxconn 不够,Workerman 还必须同步调哪些参数?
单点调大 net.core.somaxconn 会暴露其他瓶颈:
-
net.ipv4.tcp_max_syn_backlog = 65535:防止半连接队列(SYN_RECV)堆积,否则客户端 SYN 包就被丢,表现为连接超时 -
fs.file-max = 2097152和/etc/security/limits.conf中nofile设为 1048576:Workerman 每个连接占一个文件描述符,不够会报too many open files -
net.ipv4.tcp_tw_reuse = 1:对主动发起连接的 Workerman 客户端(如调用下游 HTTP 接口)至关重要,避免Cannot assign requested address - Workerman 进程数
$worker->count建议设为 CPU 核心数的 2–4 倍,但需配合压测确认——不是越多越好,进程切换开销会上升
修改后怎么确认 Workerman 真正撑住了?
光看参数写进去了没用,关键看运行态指标:
-
ss -lnt输出中目标端口的Send-Q必须是你设的值(如 65535),否则说明没生效 -
ss -lnt的Recv-Q若长期 > 1000,说明 Workerman accept 速度跟不上,得查业务逻辑是否阻塞(比如同步 MySQL 查询、sleep、未用异步日志) -
cat /proc/net/snmp | grep -i listenoverflows中TcpExt: ListenOverflows计数应为 0 或增长极慢 - 用 wrk 或 hey 对 Workerman 服务压测时,错误率突增点往往就卡在队列溢出阈值附近,这是最直接的验证
真正卡住高并发的,从来不是 Workerman 代码本身,而是内核 TCP 队列和文件描述符这两道门。漏掉任意一道,流量进来就丢,还查不到痕迹。











