worker_num设太高会因内存独占导致OOM,容器内应从2起步,按压测调至4或6;backlog需设1024并配sysctls net.core.somaxconn=4096,且Swoole≥4.8.13、启用NET_ADMIN权限才生效。

worker_num设太高反而压垮容器内存
在Docker或Kubernetes里跑Hyperf,worker_num不是照搬物理机配置就行。容器有内存限制(比如memory: 2Gi),而每个worker进程会独占一份类加载、协程栈、连接池缓存——8核宿主机设worker_num => 16,放到一个512Mi内存限制的Pod里,启动就OOM。
实操建议:
- 先查容器实际CPU可用核数:
swoole_cpu_num()在容器内可能返回宿主机总核数,得用cgroups限制后取值,推荐直接设为2起步,再按压测水位逐步加到4或6 - 用
ps aux --sort=-%mem | head -5确认单个php进程真实内存占用,若超200Mi,worker_num必须砍半 - Hyperf 3.1+ 可配合
'enable_coroutine' => true和'max_coroutine' => 10000,用协程密度替代进程数量,比盲目加worker更省内存
backlog参数没调等于放弃抗突发流量
backlog控制Swoole监听socket的**等待连接队列长度**,不是“最大并发数”。默认值通常是128,但在容器化环境(尤其用Service Mesh如Istio)下,LB与服务间多了一层转发,TCP握手延迟上升,队列积压更快。现象是:压测时curl: (7) Failed to connect to xxx port 9501: Connection refused,但swoole_server->stats()显示connection_num远低于max_conn。
实操建议:
- 在
config/autoload/server.php中显式设置:'backlog' => 1024(K8s Service默认maxSurge常为25%,1024能扛住短时流量尖峰) - 必须同步调大系统级参数:容器启动时加
sysctls: { net.core.somaxconn: 4096 },否则内核会默默截断为somaxconn值 - 验证是否生效:
ss -lnt | grep :9501看Recv-Q列能否撑到接近你设的backlog值,长期>80%说明还得调
worker_num和backlog要一起看网络栈瓶颈
单独调高worker_num却不调backlog,新连接连不上;只调backlog但worker_num太小,队列里的连接等不到处理就被超时踢掉。本质是Linux网络栈三级缓冲的协同问题:网卡队列 → socket等待队列(backlog) → worker进程调度队列。
关键检查点:
- 查
swoole_server->stats()中的accept_count和close_count差值,若持续>5000,说明连接进来但worker来不及accept,优先加worker_num - 查
netstat -s | grep "listen overflows",输出非零代表backlog溢出,被内核丢弃,必须调大 - K8s里还要看
iptables规则数——如果Service用ClusterIP且Endpoint超100个,连接建立延迟升高,此时backlog需设到2048以上
Docker/K8s环境下backlog的实际生效条件
backlog参数在容器里不是设了就起效。三个硬性前提缺一不可:
- Swoole版本≥4.8.13,旧版在
SO_REUSEPORT开启时会忽略backlog设置 - 容器必须以
hostNetwork: true或network_mode: host运行,否则Docker的netfilter劫持会绕过你的backlog队列 - 若用了
nginx-ingress或envoy,它们自身的listener_filters和per_connection_buffer_limit_bytes也得同步调大,否则瓶颈前移到代理层
最易被忽略的是:K8s Pod的securityContext.capabilities.add必须包含NET_ADMIN,否则sysctl参数无法写入,backlog永远卡在系统默认值。











