游戏卡顿白皮书 › L8 Socket 与协议
SO_REUSEPORT 分配不均 SO_REUSEPORT imbalance, stuck worker
原因 ID sk-reuseport · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
在含图示和实验的完整版中打开此卡片 →
多个进程分担同一个端口时,内核会按地址哈希给每个连接定好负责的进程,之后不再改变。负责的进程一旦停住,只有分到它那里的人在等。
起因 网关、登录服务器用 SO_REUSEPORT 起了多个进程 → 结果 即使一个进程因 GC 或过载停住,分到它的新连接和 UDP 包也不会转给其他进程 → 画面表现 只有部分人连不上、卡住。进程数变化的重启期间,部分 UDP 会话会中断
- 症状
- 连不上/无限加载, 卡住, 掉线
- 因素
- 停顿, 丢包
- 谁会遇到
- 只有我, 全服
- 何时出现
- 刚登录/维护结束后, 偶尔随机
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·系统运维
- 研发团队要做的事
- 绝不让接收线程停住;实现重启时交接会话的流程。
- 运维团队要做的事
- 监控每个进程的连接队列(ss 的 Recv-Q);发布时如果改变进程数,要走会话交接流程。
- 监控图上
- 仅部分偏高 · 每个监听 socket 的连接队列(Recv-Q)
- 查看位置
- 用 ss -ltnp 看同一端口每个监听 socket 的 Recv-Q(等待 accept 的连接数)和负责进程,对比各进程的处理量
- 确认依据
- 同一端口的多个 socket 中只有一个 Recv-Q 持续堆积,且该进程停住或处理量接近 0
- 排除依据
- 所有 socket 的 Recv-Q 都均匀堆积,是整体过载(“连接队列(backlog)溢出”)
- 确认手段
- 运维工具即可确认(无需游戏代码)
出处
- socket(7) — Linux manual page Linux man-pages
用 SO_REUSEPORT 让多个 socket 绑定到同一地址,分担 TCP 连接和 UDP 包 - net/core/sock_reuseport.c (Linux v6.12) Linux kernel
没有 BPF 程序时,按组内 socket 数对包的哈希值取模,选出负责的 socket - Why does one NGINX worker take all the load? Cloudflare
SO_REUSEPORT 用简单的哈希给每个 worker 分队列,一个 worker 堵住,堆在那个队列里的连接就全部停住 - net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
ss 的 Recv-Q、Send-Q 值:监听 socket 上是等待 accept 的连接数和 backlog 上限,已连接 socket 上是应用尚未读取的字节数和已发送但尚未收到 ACK 的字节数
相关原因
同一层:L8 Socket 与协议
其他层中同样导致“连不上/无限加载”的原因
查看含图示和实验的原卡片