한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

游戏卡顿白皮书 › 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)溢出”)
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. socket(7) — Linux manual page Linux man-pages
    用 SO_REUSEPORT 让多个 socket 绑定到同一地址,分担 TCP 连接和 UDP 包
  2. net/core/sock_reuseport.c (Linux v6.12) Linux kernel
    没有 BPF 程序时,按组内 socket 数对包的哈希值取模,选出负责的 socket
  3. Why does one NGINX worker take all the load? Cloudflare
    SO_REUSEPORT 用简单的哈希给每个 worker 分队列,一个 worker 堵住,堆在那个队列里的连接就全部停住
  4. net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
    ss 的 Recv-Q、Send-Q 值:监听 socket 上是等待 accept 的连接数和 backlog 上限,已连接 socket 上是应用尚未读取的字节数和已发送但尚未收到 ACK 的字节数

相关原因

同一层:L8 Socket 与协议

其他层中同样导致“连不上/无限加载”的原因

查看含图示和实验的原卡片