# 游戏卡顿白皮书 (Game Lag White Paper) > 本白皮书把网络游戏出现卡顿(一卡一卡、瞬移、拉回、快进、操作延迟、卡住、掉线等)的 228 个原因,从玩家画面一直到服务器数据库,分成 13 层和 3 个专题(同步设计、只有部分人遇到的问题、TCP 重传)来讲解。内容以 MMO 案例为主,但大部分与游戏类型无关,适用于各类网络游戏。每个原因都包含起因 → 结果 → 画面表现三个步骤、相关症状、数值参考、负责方(研发团队、运维团队、外部)及各团队要做的事、监控图形态和确认方法,以及权威出处(RFC,内核、操作系统、云、引擎、数据库官方文档,论文)。 原因用 ID 指代(例如 mem-gc),每个原因都有自己的页面(例如 https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-gc.html)。数值是一般线上服务环境的典型值,默认值和版本的依据见各原因页面的出处。引用时使用原因页面的地址即可。MIT 许可证。原文为韩语,本版本为译本:https://jungrok5.github.io/mmo-lag-anatomy/ ## 文档 - [完整内容(Markdown)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/llms-full.txt): 把全部原因、症状、负责方、术语和出处合成一个文件 - [纯文本版](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/text.html): 无需 JavaScript、在一个页面里阅读同样内容的 HTML - [游戏卡顿白皮书](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/): 含图示和可动手操作实验的完整版 ## 按症状查原因 - [一卡一卡](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/stutter.html): 60 个原因。动作不流畅,反复短暂停住又继续动。 - [瞬移](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/teleport.html): 47 个原因。角色没有移动过程,一下子出现在很远的位置。 - [拉回](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/rubber.html): 14 个原因。自己的角色往前走着,又被拽回刚走过的位置。 - [快进](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/burst.html): 36 个原因。停住的画面恢复后,积压的移动、打击和伤害一下子快速放完。 - [慢动作](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/slowmo.html): 24 个原因。所有东西都动得很慢,技能施放和怪物移动像被拉长了一样。视服务器设计而定,也可能速度不变,表现为一卡一卡或瞬移。 - [操作延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/delay.html): 76 个原因。按下之后要过一会儿才看到结果。画面本身可能很流畅。 - [卡住](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/freeze.html): 67 个原因。画面里的一切短暂停住(0.5 秒到数秒),然后又动起来。 - [吞操作/回档](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/dropped.html): 36 个原因。明明做了的操作像没发生过,或者结果过了好一阵又被推翻。 - [掉线](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/disconnect.html): 51 个原因。游戏中途连接断开,退回登录界面或弹出重连窗口。 - [连不上/无限加载](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/noconnect.html): 45 个原因。进不了游戏,或者停在加载、进场界面。 - [隐身/幽灵实体](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/s/invisible.html): 20 个原因。本该在的 NPC、怪物、玩家只在自己画面上看不到,或者已经消失的实体只在自己画面上还留着。 ## L1 客户端游戏进程 - [帧耗时尖峰](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-hitch.html): 某一帧的计算比平时多花了几倍时间,画面短暂停顿。 - [客户端垃圾回收](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-gc.html): 回收用完丢弃的内存(垃圾对象)期间,整个游戏会停住。特点是按固定间隔一卡一卡。 - [主线程同步加载/Shader 编译](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-sync-load.html): 第一次绘制没见过的区域、怪物、特效之前,要先读文件、生成 Shader,画面因此卡住。 - [存储设备过慢导致资源流式加载滞后](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-asset-stream.html): 在 HDD 这类慢速存储设备上,开放世界读取纹理、模型的速度跟不上移动,实体会晚出现,游戏也会因等待读取而一卡一卡。 - [大规模同屏渲染负载](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-crowd.html): 攻城战、世界 BOSS 这类数百人同屏的场景,光是绘制开销就承受不住。 - [主线程数据包处理瓶颈](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-net-mainthread.html): 收到的数据包每帧只处理固定数量时,一下子涌来的数据包会不断顺延到下一帧。 - [没有插值缓冲或缓冲过短](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-no-buffer.html): 收到服务器数据包就立刻绘制,抖动(到达间隔的波动)会原样暴露在画面上。 - [过度外推(航位推测)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-extrap.html): 数据包没到的这段时间,按最后的速度继续显示移动,发现猜错后再纠正回去。 - [客户端预测不一致](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-predict.html): 自己的客户端先把移动显示出来,服务器却算出了不同的结果,自己的角色就会被拽回去。 - [固定时间步长追赶失控](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-fixed-step.html): 停顿一次之后集中补算积压的计算,又因为这些计算再次积压。 - [时钟同步误差](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-clock.html): 客户端估算的服务器时间不准时,插值时间点和冷却判定都会错位。 - [float 时间精度丢失](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-float-time.html): 用精度较低的小数类型(float)保存游戏时间时,运行越久,时间分辨率(能区分的最小时间差)越低,动作和特效会发生颤动。 - [垂直同步(V-Sync)与渲染队列](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-vsync.html): GPU 画好的帧先在队列里攒几张,再按显示器刷新周期送出,这段时间里输入响应就会变迟。 - [客户端内存泄漏](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-leak.html): 运行越久内存占用越大,游戏越来越慢,最终被强制关闭。 - [客户端崩溃](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-crash.html): 未处理的错误导致游戏关闭。玩家看来像掉线,服务器其实正常。 - [游戏安全模块(反作弊)扫描](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/cg-anticheat.html): 为防外挂,与游戏一起运行的安全模块会定期扫描。扫描太重,或与安全服务器之间的心跳(定期发送的存活确认信号)延迟,就会一卡一卡或掉线。 ## L2 客户端操作系统与设备 - [后台进程占用 CPU](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-background.html): 杀毒扫描、Windows 更新、直播软件、浏览器视频占着 CPU 核心时,游戏线程分不到 CPU,只能等待。 - [省电模式/发热降频](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-power.html): 笔记本电池模式、手机省电模式、设备发热都会让 CPU、GPU 降速。发热的特点是一开始正常,过一阵子才变慢。 - [定时器精度](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-timer.html): Windows 默认定时器以 15.6 ms 为单位,“只休眠 1 ms”实际要等到下一个定时器周期,最长会拉长到 15.6 ms。 - [移动应用切到后台](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-mobile-bg.html): 为了看通知把应用暂时切到后台,几秒后系统就会挂起(suspend)应用,这期间服务器就会断开这个玩家的连接。 - [Wi-Fi ↔ 4G/5G 切换](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-netswitch.html): 走出家门时 Wi-Fi 断开、切换到 4G 或 5G,自己的 IP 地址会改变,原有连接随之失效。 - [安全软件检查数据包](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-security.html): 杀毒软件、防火墙逐个检查数据包会增加延迟,检查过度时还会把游戏误判为攻击并拦截。 - [接收缓冲区溢出](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-rcvbuf.html): 游戏太忙,从 socket(操作系统提供的网络收发接口)里取数据包取得晚,操作系统的缓冲区就会溢出。 - [客户端内存不足/swap](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-swap.html): 同时开着几十个浏览器标签页和游戏时,操作系统会把游戏的一部分内存换出到磁盘。 - [显存(VRAM)不足](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-vram.html): 画质选项要求的内存超过显卡显存时,操作系统要把纹理换到系统内存再取回,画面就会一卡一卡。 - [Wi-Fi 后台扫描](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-wifi-scan.html): 操作系统为了搜索周围的 Wi-Fi,会定期切换信道,这期间通信会短暂停顿。 - [网卡省电/驱动问题](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-driver.html): 有线网卡、Wi-Fi 芯片在数据包之间进入省电状态时,重新唤醒需要时间。 - [同一设备上其他应用占用带宽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-other-apps.html): 云同步、大文件下载、游戏更新在同一台 PC 上运行时,游戏数据包要在队列里排队。 - [窗口最小化/失去焦点时处理受限](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-unfocused.html): 切到别的窗口或最小化游戏时,游戏和 Windows 为了省电会让游戏降速运行。切回来时,积压的数据包会一下子涌来,或者已经掉线。 - [游戏内覆盖层干扰](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-overlay.html): 聊天软件、启动器、录屏软件、FPS 显示工具为了在游戏画面上叠加绘制自己的 UI,会介入游戏的渲染过程(hook)。每帧的工作量随之增加,偶尔还会与游戏冲突,导致顿一下或游戏被强制关闭。 - [显示器/输入设备/帧生成延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/co-display-input.html): ping 正常、操作却发沉,可能是电视的画面处理、无线手柄或帧生成功能在输入和画面之间增加了延迟。 ## L3 家庭网络 - [Wi-Fi 干扰/信号弱](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-wifi.html): 信号弱或有干扰时,无线段要重发好几次,数据包到达就会忽快忽慢。 - [Wi-Fi 信道拥挤](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-channel.html): 公寓楼这种有几十台路由器的地方,大家共用同一信道,要排队等发送机会。 - [缓冲区膨胀(路由器队列)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-bufferbloat.html): 家里有人上传视频或下载大文件时,路由器队列里会堆积几百 ms 的数据包,游戏数据包也得排在后面等。 - [NAT 映射过期](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-nat.html): 路由器会把一段时间没有数据包往来的空闲连接从 NAT 表中删除。这是挂机一段时间后一动就掉线的常见原因。 - [路由器性能不足/过热](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-router.html): 便宜的路由器上挂了几十台设备、几千条连接,路由器本身就处理不过来。 - [基站切换(移动中)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-handover.html): 坐公交、地铁移动时,切换基站期间通信会中断。 - [RRC 状态切换延迟(移动网络无线省电)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-rrc.html): 手机一段时间没有通信,就会把无线连接降到低功耗状态,下次收发数据包时要重新激活,所以会变慢。 - [手机信号弱/信号盲区](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-weak-cell.html): 在电梯、地下室、建筑物深处,重传增多、速度下降,最终掉线。 - [5G↔4G 频繁切换(5G 覆盖边缘)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-5g-flip.html): 在 5G 信号弱的建筑物内或 5G 覆盖边缘,手机会频繁在 5G 和 4G 之间来回切换,每次切换都会跳 ping 或短暂断网。 - [公共 Wi-Fi/公司网络限制](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/hn-captive.html): 咖啡馆 Wi-Fi 的登录页面或公司防火墙拦截了游戏连接。 ## L4 公网链路 - [传播延迟(物理距离)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-distance.html): 光在光纤里每秒也只能走约 20 万 km。服务器离得远,条件再好也会慢。 - [卫星互联网(低轨、静止轨道)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-satellite.html): 卫星互联网的信号要在太空中往返。静止轨道卫星光是往返就超过 0.5 秒;Starlink 这类低轨卫星平时很快,但在重新分配路径的瞬间延迟会波动,还可能短暂中断。 - [路由绕行](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-routing.html): 受运营商之间互联协议的限制,离得近的服务器也可能要绕远路才能到。 - [高峰时段对等互联链路拥塞](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-peak.html): 晚上 9~11 点前后视频流量激增,运营商之间的互联链路(对等互联)容易拥塞。 - [海底光缆/国际线路故障](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-cable.html): 海底光缆一旦中断,修好之前的几周(长则几个月)里流量要走很远的绕行路径,剩下的线路也会拥挤。 - [BGP 路由变更/收敛](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-bgp.html): 互联网的路由信息发生变化后需要重新收敛,在这几秒到几十秒(少数情况下几分钟)里会丢包。 - [ECMP 单条路径故障](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-ecmp.html): 运营商和数据中心通往同一目的地的路径往往有多条,每个连接固定走其中一条。只要有一条路径出故障,分到这条路径上的人就会一直卡。 - [运营商限速/流量管理](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-shaping.html): 套餐流量用超,或套餐对特定流量做管控时,数据包会被延后或丢弃。 - [国家/运营商级 UDP 限制与包检测](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-udp-block.html): 有些网络会封锁特定的 UDP 地址和端口,或限制 UDP 速率;包检测设备还会过滤掉它识别不了的协议。用 UDP 通信的游戏在这类网络里会连不上,或频繁掉线。 - [线路质量差](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-line.html): 接头接触不良、线路老化或调制解调器异常,会造成持续丢包和周期性的线路中断。 - [DNS 故障/延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-dns.html): DNS 负责把服务器域名解析成地址。DNS 慢或失败时,就找不到登录服务器和更新服务器。 - [DDoS 导致共享线路饱和](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-ddos-path.html): 针对游戏公司或同一网络中其他目标的大流量攻击,会把共享线路占满。 - [运营商共享 IP(CGNAT)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-cgnat.html): 移动网络和部分运营商让多个用户共用一个 IP,并会在很短时间内清掉空闲连接的映射。 - [经由 VPN/游戏加速器](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/isp-vpn.html): 开启 VPN 或游戏加速器后,数据包会经过该公司的中转服务器。中转服务器远或拥挤时,反而会变慢。 ## L5 数据中心网络设备 - [防火墙会话表耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-firewall.html): 防火墙会把放行的每个连接记到会话表里加以跟踪。表满之后就无法接受新连接。 - [DDoS 防护引流/误判](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-ddos.html): 为防御攻击把流量牵引到清洗中心后,路径会变长,还可能把正常用户误判为攻击而拦截。 - [负载均衡器空闲超时](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-lb-idle.html): 负载均衡器会在一段时间后清除空闲连接。游戏这边仍以为连接还在,结果就掉线了。 - [云安全组连接跟踪过期](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-cloud-conntrack.html): 云服务器上挂载的防火墙(安全组)同样会跟踪连接,空闲连接的跟踪条目到了规定时间就会过期。即使服务器不经负载均衡器、由玩家直接连接,挂机一段时间的玩家也可能掉线。 - [云 NAT 网关连接/端口上限](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-nat-gateway.html): 私有子网中的服务器访问外部(平台认证、支付、外部 API)时,由 NAT 网关替换地址和端口后发出。发往同一目的地的并发连接超过网关的端口上限,新连接就会失败。 - [负载均衡倾斜/健康检查误判](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-lb-imbalance.html): 连接全都挤到一台服务器上,或者一直把玩家分配到已经挂掉的服务器。 - [交换机微突发](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-microburst.html): 多台服务器在同一瞬间向数千名玩家集中发包时,这些流量汇聚的交换机端口缓冲区很小,不到 1 ms 就会溢出。 - [数据中心线路饱和](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-uplink.html): 版本更新包分发、日志传输、备份与游戏共用同一条线路时,线路会被占满。 - [网络设备故障切换(主备切换)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-failover.html): 某台路由器或防火墙发生故障、切换到备用设备(故障切换)的几秒内,所有人都会卡住。 - [线缆不良/端口错误](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-bad-cable.html): 光模块或线缆不良时,经过这条路径的数据包会按一定比例损坏。 - [MTU 不匹配(只有大包丢失)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dc-mtu.html): 中间某段的 MTU(一次能发送的最大尺寸)变小,而包过大通知又被拦截时,只有大包会一直丢失。 ## L6 服务器网卡 - [网卡中断集中在单个核心](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-irq.html): 网卡把数据包到达中断只发给一个 CPU 核心时,这个核心就会成为瓶颈。 - [环形缓冲区不足](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-ring.html): 网卡用来暂存数据包的环形缓冲区太小时,流量瞬间涌入就会溢出,数据包被丢弃。 - [中断合并过度](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-coalesce.html): 为减轻 CPU 负担,网卡把数据包攒一批再一次性通知 CPU,攒包花了多少时间,就会晚多少。 - [超出云 PPS 上限](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-cloud-pps.html): 云服务器每种规格都有每秒包数和带宽上限,超出部分会被悄悄丢弃。 - [网卡带宽饱和](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-saturate.html): 流量用到 1 Gbps、10 Gbps 网卡的极限时,发送队列会越排越长,最终数据包被丢弃。 - [虚拟化开销/邻居干扰](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-noisy.html): 同一台物理服务器上的其他虚拟机大量占用网络和 CPU 时,自己这台服务器的处理会不规律地被拖后。 - [云宿主机维护/热迁移](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-host-maintenance.html): 云厂商维护物理服务器(宿主机)时,会把虚拟机迁到其他宿主机(热迁移)或暂停片刻。这期间整台服务器停住,停住时间一长,连接就会断开。 - [网卡驱动/固件问题](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-reset.html): 驱动 bug 或某项功能异常导致网卡停住、重启,这期间所有收发都会中断。 - [GRO/LRO 合并等待延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/nic-offload.html): 这是把多个数据包合并成一个、以减轻 CPU 负担的功能。视配置而定,较小的游戏数据包可能要短暂等待下一个可合并的包。 ## L7 服务器操作系统(内核) - [连接队列(backlog)溢出](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-backlog.html): 维护结束后数万人同时连接时,内核的连接队列(backlog)会溢出,连接请求被丢弃。 - [文件描述符上限](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-fd.html): 每个连接都要占用一个文件描述符(fd,操作系统给打开的文件、socket 分配的编号),而一个进程能打开的 fd 数量是有限的。 - [内核 socket 缓冲区不足](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-sockbuf.html): 收发缓冲区太小时,一旦突发流量涌来,UDP 收到的数据包会被丢弃,TCP 发送则因缓冲区没有余量而阻塞。 - [线程过多与上下文切换](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-context.html): 线程数远多于核心数时,操作系统光是让它们轮流运行就要耗掉大量 CPU。 - [CPU 窃取时间(虚拟机)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-steal.html): 物理服务器(hypervisor)把虚拟机的 CPU 时间暂时让给其他虚拟机期间(CPU 窃取),游戏服务器会停住。 - [容器 CPU 限流(CFS 配额)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-cpu-quota.html): 给容器设置 CPU 上限后,一旦在规定周期(通常为 100 ms)内用完配额,周期剩下的时间里就会被强制停住(限流)。 - [服务器电源管理(C-state/调频)导致延迟跳变](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-cstate.html): 空闲的 CPU 核心为了省电会进入深度省电状态(C-state),频率也会降低。数据包或定时器到来时,唤醒和升频都需要时间,处理小数据包时就会多出一段延迟。 - [OOM Killer](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-oom.html): Linux 在内存耗尽时,会挑出占用内存最多的进程强制杀掉,通常就是游戏服务器。 - [内存回收/规整导致的停顿](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-reclaim.html): 操作系统为了凑出大页(huge page)而做内存规整,或为补充空闲内存而回收内存时,进程会停住。 - [系统时钟跳变(NTP step)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-timejump.html): 服务器时钟一次性向前或向后调整几秒时,依赖系统时钟的定时器会一下子集中触发或停住。 - [定时任务](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-cron.html): 每天在同一时刻运行的日志压缩、备份、安全扫描会占用 CPU 和磁盘。 - [OS/内核/驱动/固件更新后的性能变化](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-os-update.html): 游戏代码没变,服务器的 OS、内核、驱动、固件更新之后却开始变慢。更新可能会改变默认值、调度器、CPU 漏洞缓解措施(mitigations)和驱动行为。 - [服务器 conntrack 表耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-conntrack.html): Linux 防火墙会把所有连接记在连接跟踪(conntrack)表里,这张表达到上限后,新的数据包会被丢弃。 - [服务器间连接的临时端口耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/so-ports.html): 游戏服务器频繁地与 DB 或其他服务器建立短连接又断开时,断开的连接会在一段时间内占着端口,导致新连接打不开。 ## L8 Socket 与协议 - [TCP 队头阻塞](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-hol.html): TCP 为了保证顺序,在重新收到丢失的那个包之前,不会把后面已经到达的数据包交给游戏。 - [TCP RTO 与指数退避](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-rto.html): 重传每失败一次,等待时间就翻一倍,短暂的线路中断会变成长时间停顿。 - [Nagle 算法 + 延迟 ACK](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-nagle.html): 把小包攒起来再发的 Nagle 算法,和推迟发送 ACK 的延迟 ACK 叠加在一起,消息每拆开写一次,就会延迟 40~200 ms。 - [慢客户端导致的阻塞发送](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-block-send.html): 某个线路慢的玩家发送缓冲区已满时,如果用阻塞方式(缓冲区腾出空间之前调用不返回的发送)发送,服务器线程就会一直等这一个人。 - [慢客户端(slow consumer)处理策略](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-slow-client.html): 对待发送数据不断堆积的客户端,服务器会丢弃过时的更新或断开连接。 - [keepalive 默认 2 小时](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-keepalive.html): 对方没发关闭信号就消失时,TCP 要过很久才能发现。keepalive(确认空闲连接是否还活着的 TCP 功能)默认关闭,开了也要空闲 2 小时才开始确认。 - [UDP 数据包的 IP 分片](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-fragment.html): 超过 MTU(一次能发送的大小)的 UDP 包会在 IP 层分片,只要丢一个分片,整个包就被丢弃。 - [可靠 UDP 重传配置](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-reliable-udp.html): 在 UDP 之上自己实现的重传规则太保守,恢复就慢;太激进,又会让线路更堵。 - [空闲后的慢启动](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-slowstart.html): TCP 空闲一段时间后会重新缩小拥塞窗口(一次能发送的量),突然要发大量数据时只能分几次发。 - [拥塞控制导致发送量骤降](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-congestion.html): TCP 把丢包当作拥塞信号,把发送速率降低 30~50%。遇到 Wi-Fi 丢包也会同样降速。 - [RST 强制关闭导致最后的数据丢失](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-linger.html): 服务器仓促断开连接时,最后发出的提示或存盘完成信号会丢失。 - [阻塞 I/O 模型](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-blocking-io.html): 等一个 socket 时线程就干不了别的事,这种结构下人越多,整体就越慢。 - [SO_REUSEPORT 分配不均](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-reuseport.html): 多个进程分担同一个端口时,内核会按地址哈希给每个连接定好负责的进程,之后不再改变。负责的进程一旦停住,只有分到它那里的人在等。 - [Windows UDP socket 的 WSAECONNRESET 错误](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sk-udp-connreset.html): Windows 服务器向已经离开的客户端发 UDP 时,会收到“端口不可达”(ICMP)通知。这个通知会让下一次接收调用以错误结束;如果服务器代码把这个错误当作 socket 本身坏了来处理,所有使用这个 socket 的人都会受影响。 ## L9 服务器游戏进程 - [Tick 超出预算](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-tick-overrun.html): 一个 tick 内要做的事超出预算时,服务器的 tick 周期会被拉长,整个区域都会变慢或一卡一卡。 - [视野(AOI)计算激增(N²)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-aoi.html): 所有人两两比较谁能看到谁,人数变成 10 倍时,计算量就会变成 100 倍。 - [广播激增](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-broadcast.html): 把一个人的移动发给所有能看到他的人时,要发的更新数量是聚集人数的平方。 - [单线程区域过载(热点)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-hotzone.html): 每个区域由一个线程负责的架构下,人一旦聚到一处,只有那一个核心会跑到 100%。 - [锁竞争](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-lock.html): 多个线程为了写同一份数据而等同一把锁时,线程再多,一次也只有一个在执行。 - [死锁](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-deadlock.html): 两个线程互相等待对方持有的锁,就会永远停住。 - [游戏线程中的同步调用](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-sync-call.html): tick 中途等待 DB 响应或文件写入时,等多久,服务器上整个游戏的运行就停多久。 - [消息队列积压](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-queue.html): 请求进来的速度超过处理速度、在队列里堆积时,排在后面的请求要过几秒才被处理,或者被丢弃。 - [定时器集中触发](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-timer-burst.html): 所有怪物刷新、所有 buff 到期、整点奖励都挤在同一个 tick 时,那个 tick 的负载就会高出几十倍。 - [寻路计算激增](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-pathfinding.html): 几百只怪物同时追着玩家计算路径时,会占用大量 CPU。 - [序列化/压缩开销](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-serialize.html): 把要发送的数据转换成字节并压缩也要消耗 CPU,人多时这部分开销会暴增。 - [服务器崩溃](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-crash.html): 服务器进程因未处理的错误而崩溃时,这台服务器上的所有人会同时掉线。 - [线程池耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-threadpool.html): 处理任务的工作线程全被慢操作占住时,新请求只能干等。 - [死循环/逻辑失控](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-infinite-loop.html): bug 导致一个 tick 无法结束时,服务器会停住,然后被看门狗强制重启。 - [战斗集中在单一目标(世界 BOSS)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-hot-entity.html): 几百人同时打一个 BOSS 时,这一只 BOSS 的计算全压在一处,命中信息还要发给所有看得到的人。 - [进入密集区域时实体生成激增](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-spawn-burst.html): 传送到挤满人的城镇时,服务器要把新进入视野的几百人的外观、装备、状态一次性发过来。 - [实体堆积(未清理的物品/召唤物)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-entity-buildup.html): 本该消失的地面物品、召唤物、已结束的定时器没有被清理而不断堆积,服务器开得越久,每个 tick 要做的事就越多。 - [版本更新导致流量特征变化](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sp-patch-traffic.html): 新内容、特效、同步项增加了数据包的大小和频率,原本正常的服务器在版本更新后开始碰到 MTU、带宽、包数的上限。 ## L10 内存 - [服务器 GC 全局停顿](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-gc.html): Java、C# 服务器为回收垃圾对象而暂停所有线程(stop-the-world),这段时间里整个服务器都停住。 - [脚本引擎 GC 停顿](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-script-gc.html): 即使是 C++ 服务器,如果任务、AI、技能用 Lua 等脚本来跑,脚本引擎执行 GC 期间,对应的场景也会停住。 - [内存分配暴增](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-alloc.html): 活动期间大量创建临时对象,GC 会比平时频繁得多。 - [内存泄漏](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-leak.html): 没有释放的内存一点点累积,几天后引发 GC 失控、swap 或进程被强制终止。 - [GC 颠簸(堆余量不足)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-gc-thrash.html): 存活数据接近堆上限时,GC 即使运行也几乎回收不到东西,于是不停地反复执行。 - [swap](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-swap.html): 内存不足时,OS 会把一部分内存换出到磁盘。之后每次用到这部分内存,都要等待比内存慢 1,000 倍以上的磁盘。 - [缓存未命中](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-cache-miss.html): 数据分散在内存各处时,CPU 每次都要到较慢的内存里取数据并等待。 - [内存碎片](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-fragment.html): 反复分配和释放会把空闲空间切得很碎,进程占用的内存会远多于实际使用量。 - [NUMA 远端内存](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/mem-numa.html): 在装有两颗 CPU 的服务器上,使用挂在另一颗 CPU 上的内存,访问会变慢。 ## L11 磁盘 - [同步写日志](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-sync-log.html): 游戏线程每写一行日志都要等磁盘完成,磁盘一忙,游戏逻辑也跟着停住。 - [fsync 风暴](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-fsync.html): 要求把数据“真正”写进磁盘(确保落盘)时,视磁盘不同每次要花 0.1 ms 到几十 ms;请求一集中,队列就会变长。 - [云盘突发积分耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-burst.html): 部分云盘和小规格实例有突发积分,可以短时间超过基准性能运行。繁忙时段一长、积分耗尽,速度就会突然下降。 - [IOPS 上限/队列饱和](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-iops.html): 请求超过磁盘每秒能处理的数量后,队列变长,延迟暴涨。 - [磁盘写满](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-full.html): 日志和 dump 堆积把磁盘写满后,写入会失败;没有做好应对,服务器就会崩溃。 - [备份/压缩/扫描任务](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-backup.html): 凌晨的备份、日志压缩、安全扫描独占磁盘时,游戏服务器的读写会被挤到后面。 - [服务器端懒加载](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-lazy-load.html): 服务器第一次收到副本、地图数据请求时才从磁盘读取,那个 tick 期间所有人都会卡住。 - [写入 core dump](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-coredump.html): 服务器崩溃时要把数 GB 内存写到磁盘,重启有时会因此推迟好几分钟。 - [HDD 寻道延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/dk-hdd.html): HDD 的磁头必须在盘片上移动(寻道,seek),读写分散的数据每次要花将近 10 ms。 ## L12 数据库 - [缺少索引的查询](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-no-index.html): 没有索引时,要找到符合条件的行,就得把整张表读一遍(全表扫描)。 - [热点行锁竞争](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-hot-row.html): 所有人都要修改同一行(公会仓库、拍卖行热门物品、全服计数器)时,同一时刻只有一个人能拿到锁。 - [DB 死锁](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-deadlock.html): 两个事务(作为一个整体处理的一组 DB 操作)互相等待对方锁住的行时,DB 会强制取消其中一个。 - [连接池耗尽](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-pool.html): 与 DB 建立的连接数是固定的,慢查询占住连接后,其余请求只能等待。 - [复制延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-replica-lag.html): 写入走主库、读取走从库时,如果从库同步落后,刚写入的内容就读不到。 - [检查点/日志刷盘](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-checkpoint.html): DB 定期把内存中的变更集中写入磁盘,那一刻查询会变慢。 - [冷缓存(刚重启时)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-cold-cache.html): DB 重启后内存缓存是空的,一段时间内所有查询都要从磁盘读取。 - [登录激增与 N+1 查询](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-login-storm.html): 加载一个角色要分别查询几十次时,数万人同时登录就会变成几百万条查询。 - [大型批处理任务](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-batch.html): 在运营期间跑排行榜统计、批量发邮件、清理旧数据,会占用锁和磁盘。 - [DB 故障切换](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-failover.html): 主库宕机、切换到备库期间无法写入,最后一部分没来得及复制的数据可能会丢失。 - [存盘间隔过长导致进度丢失](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-save-interval.html): 为减轻负载,几分钟才存一次盘,期间服务器一旦崩溃,进度就会丢失。 - [缓存雪崩](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-cache-stampede.html): 热门数据的缓存同时过期时,几千个请求会一下子涌向 DB。 - [长事务](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-long-tx.html): 一个事务长时间不结束,就会一直持有锁,DB 也没法清理(purge)旧版本数据,整体逐渐变慢。 - [Redis 慢命令](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-redis-block.html): Redis 一次只处理一条命令,一条慢命令就会挡住后面所有请求。 - [执行计划变化导致查询变慢](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-plan-flip.html): 代码没变,DB 却换了处理同一条查询的方式(执行计划),昨天 2 ms 的查询今天就变成几百 ms。 - [线上表结构变更(DDL)锁](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/db-ddl-lock.html): 在服务运行中给表加列或加索引,仅仅因为一个短暂需要的锁,使用这张表的所有请求都可能被迫等待。 ## L13 服务器架构与运维 - [经由网关/代理](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-gateway.html): 在客户端和游戏服务器之间加一层中间服务器,每经过一次就多一段处理时间,这台服务器也会成为单点故障。 - [场景切换(服务器间迁移)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-zone-transfer.html): 进入其他区域或副本时,要把角色数据交给另一台服务器,这个过程中会出现延迟和失败。 - [级联故障](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-cascade.html): 一个服务变慢,调用它的服务器都会因等待响应而被占住,连不相关的功能也会停摆。 - [辅助服务器故障](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-subservice.html): 聊天、组队、拍卖行这类与游戏服务器分开运行的服务器出故障时,只有对应的功能不能用。 - [发布/重启](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-deploy.html): 为更新而重启服务器时,如果不迁移连接,这台服务器上的玩家都会掉线,关机前的存盘和随后的重连也会一下子挤在一起。 - [弹性伸缩延迟](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-autoscale.html): 人一多就会自动增加服务器,但准备要几分钟,这段时间现有服务器处于过载状态。 - [日志/监控过载](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-monitoring.html): 出故障时日志会激增,同步发送日志的服务器会被日志拖得更慢。 - [服务器之间的时钟差](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-clock-skew.html): 每台服务器的时钟略有差异时,冷却、buff、活动开始的判定在不同服务器上就会对不上。 - [脚本/机器人过多](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-bots.html): 机器人发请求的频率远高于真人,会吃掉服务器的处理能力。 - [依赖外部服务](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-external.html): 平台登录、支付、实名认证这类外部服务变慢或停摆时,流程会卡在那一步。 - [匹配/区域分配错误](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-region-match.html): 没有分到近的区域(region),被分到远区域的服务器,即使线路正常,也只有这个玩家 ping 一直偏高。 - [TLS 证书过期/配置错误](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-cert.html): 登录、API、补丁服务器的证书过期或缺少中间证书时,从那一刻起新建连接的客户端 TLS 连接都会失败。 - [登录排队上限/重连保留不足](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/in-login-queue.html): 上线、维护结束后连接集中涌入时,登录排队达到上限,开始拒绝新的排队;正在排队的玩家只要短暂断开一下就会丢掉位置,回到队尾。 ## 同步设计 - [收到服务器响应才播放表现(请求-响应方式)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-request-response.html): 按下按钮后,在服务器回复之前既没有动画也没有声音。ping 值直接就是反应速度。 - [顺序往返多的协议(chatty)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-chatty.html): 一次操作需要依次与服务器往返多次时,ping 就要乘以这个次数。 - [技能不支持预输入](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-no-queue.html): 必须等服务器确认上一个技能结束后才能按下一个技能时,每次衔接中间都会插入一段往返时间。 - [被 ping 吃掉的短判定窗口](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-short-window.html): 闪避、弹反、格挡这类需要反应的时间很短时,ping 会把这段时间吃掉,出现躲不开的攻击。 - [没有延迟补偿的判定](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-no-lagcomp.html): 服务器只按“当前服务器上的位置”判定命中时,自己看到的画面就会与判定结果对不上。 - [延迟补偿过度](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-lagcomp-overreach.html): 按攻击者的视角回溯得太远时,被打的一方明明已经躲好了,还是会被打中。 - [客户端权威](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-client-auth.html): 各自决定自己的结果,自己的画面很流畅,但结果会与别人的画面对不上,也容易被外挂利用。 - [帧同步中等待最慢的玩家](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-lockstep.html): 所有人一起计算同一个逻辑帧的结构下,只要有一个人的输入晚到,所有人都得等。 - [回滚网络代码预测失败](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-rollback.html): 先预测对手的输入并显示出来,猜错了就回滚重新计算。ping 越高,回滚的幅度越大。 - [没有时间戳、一到就播放](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-no-timestamp.html): 服务器事件不附带发生时刻、一收到就播放时,网络抖动会原封不动地让表现时机忽快忽慢。 - [双重 tick 等待](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-double-tick.html): 请求攒到下一个 tick 才处理,结果又在再下一个 tick 才发出,tick 间隔就被叠加了两次。 - [过于严格的服务器校验](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-strict-check.html): 服务器对移动速度、冷却、射程检查得过于严格时,连因抖动扎堆到达的正常输入也会被拒绝。 - [主机(房主)结构](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-host.html): 由某个玩家的电脑充当服务器时,这个人的线路和电脑性能决定了所有人的体验。 - [预表现后被服务器拒绝](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-optimistic-reject.html): 在自己画面上先显示出来的命中、技能,服务器事后不认可时,明明看到的结果就当没发生过。 - [指令同步的路径计算不一致](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-path-mismatch.html): 只互传“去这里”,路径由双方各自计算时,计算稍有差异,角色或怪物就会走上另一条路,然后被拽回原位。 - [快照发送频率低](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/sy-low-send-rate.html): 服务器每秒只发几次位置更新(快照)时,插值缓冲就得相应拉长,看到的其他角色也就是更久以前的状态。 ## 只有部分人遇到的问题 - [网络差的玩家在别人画面上快进移动](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-slow-burst.html): 线路差的人,输入会忽多忽少地扎堆到达服务器。服务器每个 tick 收到多少就应用多少时,在别人眼里,这个角色会顿一下,然后一下子走出好几步。 - [到达即处理的服务器造成的快进](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-event-server.html): 在包一到就立即处理并广播的服务器上,网络差的人扎堆到达的动作会被接连立即执行。 - [每个玩家的输入缓冲大小](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-input-buffer.html): 服务器为每个人先攒一点输入,每个 tick 取出一个使用时,别人看起来很流畅,但本人动作在服务器上确定的时间也会相应推迟。 - [集中在特定运营商玩家身上的校验误判](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-isp-validation.html): 使用抖动大的线路的人,输入会扎堆到达,经常触发服务器的速度、冷却检查。 - [一个网络差的队友与 BOSS 机制](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-raid-member.html): 在需要所有人在规定时刻一起反应的团本机制中,一个网络差的人反应晚了,就会让整个队伍失败。 - [怪物控制权在慢的客户端上](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-mob-control.html): 有的游戏为减轻服务器负载,把怪物的移动计算交给附近某个玩家的客户端。这个人的线路差时,这只怪物在所有人的画面上都会动得很怪。 - [特定角色数据过于庞大](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-heavy-char.html): 物品、邮件堆了几千个,或者好友列表、黑名单、buff 特别多的角色,登录、存盘、向周围广播的数据量是别人的好几倍。与线路无关,只有用这个角色时才慢。 - [分线/副本/位面不同](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-phase.html): 两个角色在不同的分线或副本里,或者处在按任务进度显示不同 NPC 的不同“位面”时,看到的就是不同的世界。 - [加载中到达的出现通知被丢弃](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-loading-drop.html): 刚进入场景,服务器就发来周围 NPC 的出现通知,而客户端还在加载地图,就把这些通知丢掉了。 - [视野注册顺序错乱](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-aoi-race.html): 角色注册到视野网格的时刻与 NPC 跨网格移动的时刻重合时,这个 NPC 的出现通知可能会漏掉。 - [基准快照丢失](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-baseline.html): 在服务器只发“与上次相比变化的部分”的方式下,丢了最初那一份完整信息(基准),之后的变化量就没法应用。 - [离开通知丢失(幽灵实体)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-ghost.html): 反过来,漏掉“已消失”的通知时,已经死亡或离开的 NPC、玩家只会留在自己的画面上。 - [刚进入时集中到达的出现信息丢失](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-spawn-burst.html): 进入场景的那一刻,服务器会一次性发出周围几十到几百个实体的出现信息。如果用不可靠(unreliable)通道发送,或者客户端在加载中读不了 socket、接收缓冲区溢出,就会丢掉一部分,而且不会再来。 - [实体 ID 重用混淆](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-id-reuse.html): 死掉的 NPC 重新出现时,如果服务器重用同一个实体 ID,期间漏掉离开通知的客户端会把新 NPC 误认成旧 NPC。 - [固定 UDP 端口冲突](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-port-collision.html): 客户端被做成使用固定的本地端口时,同一台电脑上的第二个客户端要么用不了这个端口,要么和第一个客户端分着收包。 - [按 IP/设备区分会话的 bug](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-session-key.html): 服务器或中间服务器按 IP 或设备 ID 区分连接时,会把同一台电脑(同一公网 IP)上的两个客户端认成同一个人。 - [多开限制](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-multiclient.html): 安全模块或服务器策略限制一台电脑上开多个客户端时,第二个客户端会无法启动或连接,或者先开的那个掉线。有些游戏只禁用额外客户端的部分功能。 - [后台窗口处理受限](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-background.html): 处于后台窗口的客户端,游戏、引擎、OS 都会减少它的帧和处理量。收到的包不能及时处理,就会积压或溢出。 - [缓存/资源文件并发访问冲突](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-asset-lock.html): 两个客户端同时写同一个缓存文件夹或锁住文件时,其中一个会加载不了 NPC 模型、纹理。 - [内存/显存不足导致流式加载失败](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-vram.html): 两个客户端共用显存时,新需要的模型、纹理没有地方加载,有一部分就画不出来。 - [显示选项不同](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-display-option.html): 显示人数限制、隐藏 NPC 名字牌或模型、低配模式这类选项在两个客户端上不同时,看到的东西就不一样。 - [客户端版本/数据不一致](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-version.html): 第二个客户端来自另一个安装目录,或补丁没打完时,它不认识服务器发来的新 NPC ID,就会悄悄忽略。 - [按连接分配的发送预算/优先级](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-priority.html): 服务器给每个连接的发送量设上限、按由近及远的顺序发送时,上限定得低的一方收到远处 NPC 会很晚,甚至收不到。 - [时钟估算误差导致实体被搁置](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/pt-clock-hold.html): 客户端估算的服务器时间不准时,刚到达的实体信息会被当成“还在未来”而搁置,或被当成“太旧”而丢弃。 ## TCP 重传的根本原因 - [无线链路丢包](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-wireless.html): Wi-Fi 和移动网络会在无线链路上重传几次,仍然失败就丢弃数据包。被丢弃的包要等过好一阵,才由 TCP 重新发送。 - [瓶颈队列溢出(拥塞丢包)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-queue-drop.html): 路由器、运营商之间的互联链路、数据中心线路这类最窄处的队列一旦满了,新来的数据包就会被丢弃。 - [突发发送导致浅缓冲区溢出](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-burst.html): 服务器每个 tick 在一瞬间集中发出几千人份的更新,交换机的小缓冲区或云平台的瞬时上限不到 1 ms 就会溢出,一部分包被丢弃。 - [流量监管丢弃超额流量](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-policer.html): 运营商套餐限速、云实例上限和 DDoS 防护设备,有时会把超过规定速率的数据包直接丢弃,不放进队列。 - [物理层错误(线缆/光模块/连接器不良)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-physical.html): 线缆损坏、光纤连接器积灰、光模块老化都会产生误码,损坏的数据包会被设备悄无声息地丢弃。 - [双工不匹配](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-duplex.html): 一端用自动协商,另一端把速率和双工写死,就会有一端以半双工工作,每当负载上来就因冲突丢包。 - [接收端服务器主机丢包](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-host-drop.html): 数据包已经到了服务器,却因网卡的环形缓冲区(暂存到达数据包的缓冲区)溢出,或内核中负责接收处理的 CPU 核心饱和而被丢弃。 - [防火墙/连接跟踪丢包](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-stateful-fw.html): 防火墙或 Linux 连接跟踪(conntrack,把经过的连接记录到表里的功能)在表满了,或判断连接状态不对时,会丢弃数据包。 - [中间设备超出处理上限(防火墙/IPS/DDoS 防护)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-appliance-pps.html): 防火墙、入侵防御设备(IPS)、DDoS 防护设备会逐个检查经过的数据包。一旦超出检测能力,处理不过来的包就会被丢弃。 - [MTU 黑洞(只有大包反复丢失)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-mtu.html): 中间链路能通过的包变小了,“包太大”的通知(ICMP)却被拦截,大包无论重发多少次都会丢失。 - [连接中途 NAT/负载均衡器映射过期](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-mapping.html): 中间设备删掉空闲连接的映射(记录该连接应转发到哪里的条目)后,之后发出的包就送不到了。要么反复重传后掉线,要么设备回一个拒绝连接的 RST,立刻断开。 - [路径变更/ECMP 故障路径](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-path.html): 互联网路由切换的几秒内,或者被分配到多条 ECMP 路径中某条故障路径的连接上,会出现丢包。 - [延迟飙升导致的虚假重传](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-spurious-delay.html): 数据包只是一时到得特别晚,并没有丢。但只要这段延迟超过 RTO,发送方就会判定为丢包并重传。 - [乱序导致的虚假快速重传](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-reorder.html): 数据包经过多条路径或聚合链路时顺序被打乱,接收方会用重复 ACK 通知“有包缺失”,发送方就把好好的包又发一遍。 - [ACK 延迟或丢失(上行饱和)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-ack-path.html): 数据已经顺利到达,但表示“已收到”的 ACK 在塞满的上行队列里被耽搁或丢掉,发送方就会判定为丢包并重传。 - [RTO 设置与环境不匹配](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-rto-setting.html): RTO 最小值调得太低,稍微晚一点就会产生虚假重传;默认值(200 ms)对游戏来说又太长,每丢一次包都要停顿很久。 - [thin stream 恢复慢](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-thin.html): 像游戏这样稀疏地发小包时,还没等到“后续 3 个包”,RTO 就先到期了。同样的丢包,停顿时间比大流量传输长得多。 - [中间设备剥离 TCP 选项](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-sack-stripped.html): 部分防火墙或加速设备删除或改写 TCP 选项后,丢多个包时每个往返只能恢复一个,或者窗口(一次能发送的量)变小,速度变慢。 - [零窗口(看起来像重传的停顿)](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-zero-window.html): 接收方程序没有及时读取 socket,缓冲区满了之后,发送方就会停止发送,只发零窗口探测。这与线路无关。 - [连接请求(SYN)重传](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/c/rt-syn.html): 连接请求因连接队列(backlog)溢出或被防火墙拦截而丢失时,客户端操作系统会从 1 秒后开始,以逐渐拉长的间隔重发。 ## 判定与案例 - [用观测数据判定](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/#judge): 按范围 → 时间点 → 层级的判定流程、判定信号表、13 种监控图形态、数字怎么看(平均值与 p99) - [分场景排查流程](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/text.html#playbooks): 版本更新后卡顿、新增海外国家/地区 - [真实故障案例](https://jungrok5.github.io/mmo-lag-anatomy/zh-cn/text.html#cases): 原开发商、运营方公开的故障复盘及相关原因 ## 其他语言 - [한국어 (Korean)](https://jungrok5.github.io/mmo-lag-anatomy/llms.txt) - [English](https://jungrok5.github.io/mmo-lag-anatomy/en/llms.txt) - [日本語 (Japanese)](https://jungrok5.github.io/mmo-lag-anatomy/ja/llms.txt) - [繁體中文 (Chinese (Traditional, Taiwan))](https://jungrok5.github.io/mmo-lag-anatomy/zh-tw/llms.txt) - [Deutsch (German)](https://jungrok5.github.io/mmo-lag-anatomy/de/llms.txt) - [ไทย (Thai)](https://jungrok5.github.io/mmo-lag-anatomy/th/llms.txt) - [Tiếng Việt (Vietnamese)](https://jungrok5.github.io/mmo-lag-anatomy/vi/llms.txt) - [Русский (Russian)](https://jungrok5.github.io/mmo-lag-anatomy/ru/llms.txt) - [Português (Brasil) (Portuguese (Brazil))](https://jungrok5.github.io/mmo-lag-anatomy/pt-br/llms.txt) - [Español (Spanish)](https://jungrok5.github.io/mmo-lag-anatomy/es/llms.txt) - [Bahasa Indonesia (Indonesian)](https://jungrok5.github.io/mmo-lag-anatomy/id/llms.txt) ## Optional - [GitHub 仓库](https://github.com/jungrok5/mmo-lag-anatomy): 源码、数据格式、参与贡献的方法 - [作者:Jeongrok Oh](https://jungrok5.github.io/resume/en/): 简历