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

游戏卡顿白皮书 › L7 服务器操作系统(内核)

连接队列(backlog)溢出 Listen backlog / SYN queue overflow

原因 ID so-backlog · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维, 研发团队·客户端开发

在含图示和实验的完整版中打开此卡片 →

维护结束后数万人同时连接时,内核的连接队列(backlog)会溢出,连接请求被丢弃。

起因 维护一结束,连接涌入的速度就超过了游戏服务器用 accept 处理连接的速度 → 结果 内核的连接队列(backlog,取服务器代码传给 listen 的值与内核上限中较小的一个)已满 → 画面表现 连接请求被丢弃,客户端反复重试,表现为连不上/无限加载

症状
连不上/无限加载
因素
丢包
谁会遇到
全服
何时出现
刚登录/维护结束后
负责方
主责 研发团队·服务器开发 · 配合 运维团队·系统运维, 研发团队·客户端开发
研发团队要做的事
服务器:调大代码里传给 listen 的值;不要让接受连接的线程因为其他工作而停住;做登录排队系统。客户端:拉长重试间隔(随机打散)。
运维团队要做的事
调大内核 somaxconn(要和服务器代码里的 listen 值一起调大才有效);保持 SYN Cookie 开启;监控溢出次数(nstat 的 TcpExtListenOverflows)。
数值参考
Linux 内核上限(somaxconn)从 5.4 起默认为 4,096(之前为 128),但服务器代码传给 listen 的值更小时,以这个值为上限。Linux 在队列满时会不报任何错误,悄悄丢弃连接请求。客户端操作系统会从 1 秒后开始重发几次,所以玩家看到的往往是长时间加载,很少直接出现“连接失败”。Windows 服务器则会回复拒绝,客户端马上就会看到“连接失败”。
监控图上
开服/维护后激增 · 连接队列溢出次数(ListenOverflows)、连接请求数
查看位置
看 nstat -az 中 TcpExtListenOverflows、TcpExtListenDrops 的增量,用 ss -ltn 对比监听 socket 的 Recv-Q(等待 accept 的连接数)和 Send-Q(backlog 上限)
确认依据
连接集中涌入的时刻 ListenOverflows 增加,监听 socket 的 Recv-Q 贴着 Send-Q 的值
排除依据
ListenOverflows 没有变化则不是这个原因。连接已经建立但加载一直不结束,看“登录激增与 N+1 查询”;人数一到某个固定值就进不来,看“文件描述符上限”
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. listen(2) — Linux manual page Linux man-pages
    listen 的 backlog 超过 somaxconn 时会被悄悄截断;somaxconn 默认 4,096(从 5.4 起,之前为 128);队列满时可以忽略请求,交给客户端重试
  2. IP Sysctl Linux kernel
    tcp_syn_retries:连接请求(SYN)首次重传等待 1 秒,会重发多次;tcp_abort_on_overflow 默认关闭(溢出时也不回复拒绝);tcp_syncookies 默认开启
  3. listen function (winsock2.h) Microsoft
    Windows 在队列满时,客户端会收到 WSAECONNREFUSED 错误
  4. SNMP counter Linux kernel
    TcpExtListenOverflows:因 accept 队列已满而丢弃连接请求(SYN)的次数,此时 TcpExtListenDrops 也会一起增加
  5. net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
    ss 的 Recv-Q、Send-Q 值:监听 socket 上是等待 accept 的连接数和 backlog 上限,已连接 socket 上是应用尚未读取的字节数和已发送但尚未收到 ACK 的字节数

相关原因

同一层:L7 服务器操作系统(内核)

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

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