了解Edgegap的工作原理

了解Edgegap的工作原理

网络代码基础:Ping、滴答率(Tick Rate)与网络模型详解

已发布

已发布

已发布

Edgegap 洞察系列横幅,上面写有“网络代码基础”(Netcode Fundamentals),并配有一个瀑布图预览,展示了一名玩家的输入与另一名玩家屏幕显示之间,网络、服务器和客户端延迟是如何累加的。

核心洞察

核心洞察

核心洞察

  • 延迟存在下限,其余一切都在其之上累加:两台机器之间的物理传输时间是任何网络游戏所能达到的最小延迟。路由、Tick率、更新率和处理过程都会增加延迟。网络代码无法消除这种延迟,它只能决定玩家在何处感知到它。

  • 最短路径很少是最快的:直接的P2P(点对点)连接看似是两名玩家之间的最短路径,但数据包仍需经过双方的互联网服务提供商(ISP)以及这些网络所选择的任何路由。在他们之间放置一台位置合理的服务器,往往既更快又更公平。

  • 延迟补偿转移了代价,并未将其消除:延迟补偿会回溯服务器状态以判定高Ping玩家的射击有效,这意味着目标玩家在进入掩体后仍可能被击中。唯一真正的解决办法是缩小Ping值差距,这使其既是网络代码问题,也是匹配机制和服务器布局问题。

  • Tick率是时间预算:服务器的Tick率决定了它模拟游戏每个步骤所拥有的毫秒数。更高的速率可以减少延迟并提高命中判定的精准度,但会消耗更多的CPU和带宽。超出时间预算的服务器会导致对局中的每个人都出现卡顿。

  • 这是两个独立的选择,而非一个:游戏在哪里运行(P2P、中继或专用服务器)与状态如何共享(锁步、回滚或状态同步)是互不相关的决定。任何同步模型都可以在任何托管模型上运行。

这是关于在线多人游戏网络代码(Netcode)核心构件的基础入门指南。在全文中,我们为每个术语都附上了词汇表定义链接,同时提供了“后端深度解析”系列文章,展示这些概念如何在知名多人游戏中落地应用。

什么是网络代码(Netcode)?

网络代码是负责在相隔数毫秒的不同设备之间保持多人对战一致性的网络程序代码。它并不能孤立运行。网络代码只是更庞大生态系统中的一层,与服务器托管、编排和匹配系统协同工作,共同提供在线多人游戏体验。我们的《使命召唤》网络代码解析文章展示了这些层级在实际游戏中是如何交互的。

网络代码本身可以细分为七个部分:

  • 传输层(Transport):传输数据包的协议,对于实时游戏几乎都是 UDP。

  • 模拟循环(Simulation loop):服务器推进游戏世界的频率(即 Tick 率 / tick rate)。

  • 状态同步/复制(Replication):向每位玩家发送哪些数据以及发送频率(更新率)。

  • 权威性(Authority):哪台机器对发生的事件拥有最终决定权,通常是权威服务器。

  • 托管架构(Hosting model):权威模拟在何处运行,是在玩家的机器上(点对点 / P2P)、位于中继服务器之后,还是在专用服务器(Dedicated server)上。

  • 同步模型(Sync model):各设备如何保持一致,通过帧同步(Lockstep)、回滚(Rollback)还是状态同步。

  • 延迟掩盖(Latency hiding):客户端预测、服务器校准、实体插值和延迟补偿,这些技术让玩家感知不到网络延迟的存在。

Waterfall diagram titled "Where the Milliseconds Go", tracing one player input to another player's screen in eight steps: travel to server, routing detours, wait for next tick, simulate, wait for next send, travel to other player, routing detours, and interpolation buffer. Each step starts where the last one ended, and a total delay bar shows them combined. Physical travel is the minimum delay set by distance. Routing is reduced by server placement, the server clock by tick and update rate, and client smoothing is tuned by netcode. Note: for illustration only, not to scale.

客户端/服务器网络代码的起源

大多数现代射击游戏的网络代码都可以追溯到一款游戏。初代《雷神之锤》(Quake,1996)采用了纯客户端/服务器架构设计:客户端将输入发送给服务器,然后等待服务器告知发生的结果。每个客户端本质上都只是显示服务器世界的一个终端。

在局域网环境下,这种方式完全可行。但在互联网上,它就行不通了。

时任 id Software 首席程序员的约翰·卡马克(John Carmack)在 1996 年 8 月的开发日志中写道,他“在制作优秀的互联网游戏时采用了错误的基本假设”。最初的设计“针对的是小于 200 毫秒的连接延迟”,而拨号上网玩家面对的“至少是 300 毫秒以上的延迟”。在纯客户端/服务器模式下,屏幕上的任何动作发生前,每次按键都必须等待一个完整的往返时间。

他在《QuakeWorld》中提出的解决方案奠定了沿用至今的模型。客户端现在会“预先猜测用户移动的结果,直到来自服务器的权威响应送达”。服务器依然保持绝对权威,而客户端进行预测。

在同步模型层面(下文会详细介绍),《QuakeWorld》使用了状态同步:服务器发送世界的状态,每个客户端在下一次更新到达之前预测自己的移动。这不同于帧同步,后者需要每台机器在继续推进前等待其他所有人的输入。

这种结合——权威服务器加上客户端预测——成为了后人构建网络架构的基石。《部落》(TRIBES,1998)增加了同步的 32 毫秒 Tick、其他玩家插值,并在连续三个数据包中发送输入数据。二十年后,《守望先锋》(Overwatch)仍在使用滑动输入窗口,其开发者直言该技术可以追溯到《QuakeWorld》。

什么是 Ping?它与 Lag(卡顿/延迟)有何不同?

Ping 是一种度量值。你的设备向另一台设备发送一个小型数据包,对方做出回复,发送与接收之间的时间就是往返时间(RTT)。关于面向初学者的基础指南,请参阅 Edgegap 关于游戏中什么是延迟(Latency)的解析。

Lag 是延迟带来的后果。它是你在屏幕上看到的画面与服务器以及其他玩家在他们屏幕上看到的画面之间的差距。

Lag 不仅仅是一种主观感受。在 Edgegap 的延迟报告中,50% 的玩家将 Lag 列为在线游戏中最令人沮丧的第一大痛点,34% 的玩家表示他们曾因此彻底放弃某款游戏。

存在一个任何网络代码都无法突破的物理下限。数据在铜线和光纤中的传输速度是有限的,因此延迟绝不可能低于两台设备之间的物理传输时间。其他所有因素都会在这个底线之上增加延迟。

其中增加最多通常是路由。数据包从来不会沿直线传输。它们必须穿过由不同网络运营商拥有的路由器链路,每一跳(Hop)都会增加时间。这就是为什么分布式云基础设施首先要考虑服务器在物理上部署在哪里。

这也是直觉往往出错的地方。在双人比赛中,直连的点对点连接看起来是可能的最短路径——中间没有服务器,只有两名玩家之间的连接。

但在实践中,“直连”仍意味着要离开一名玩家的家庭网络,经过其 ISP(网络服务提供商),再穿过另一名玩家的 ISP,最后到达可能处于 Wi-Fi 环境下的普通民用网络连接。如果加入更多玩家,其中一人就必须作为主机,这会导致主机拥有零延迟,而其他所有人面临各不相同的延迟。在所有玩家之间妥善部署一台处于中立位置的服务器,不仅能消除主机的先天优势,通常还能缩短实际的路由路径。下一节将解释其中的原因。

为什么仅凭距离无法预测 Ping?

相距仅 50 公里的两名玩家之间仍然可能存在糟糕的网络连接。真正起决定作用的是数据包实际行经的路由。

拳头游戏(Riot Games)的工程团队在 2015 年构建自己的专用游戏网络时记录了这一点。他们解释道,骨干网提供商和 ISP“往往优先选择成本更低的路由,而不是速度更快的路由”。在一条从旧金山到波特兰的连接中,“直连路径可能只需要 14 毫秒,但效率较低的路由却耗费了整整 70 毫秒”。

距离决定了理论下限,而路由决定了你最终会超出这个下限多少。

选择服务器位置时也遵循同样的逻辑。离某个玩家近并不是目标;真正的目标是找到能让比赛中的每一位玩家都获得最佳且最均衡连接的位置。

Edgegap 与一家排名前五的发行商合作进行的 1v1 格斗游戏案例研究对此进行了衡量。通过在最佳可用位置按需为每场比赛部署服务器,而不是使用一组固定的公有云区域,对手之间的延迟差距从 46.5 毫秒缩小到 33 毫秒,公平性提高了 28%。91% 的玩家迎来了更低的延迟。

这就是支持更多节点位置的理由:服务器可以启动的地点越多,就越有可能找到一条对所有人来说都短且均衡的路由。正因如此,Edgegap 的网络目前覆盖了全球 615 多个地点。

为什么一个高 Ping 玩家会影响所有人?

在射击游戏中,高 Ping 玩家瞄准的是他们看到的过去的目标位置。如果服务器只根据当前时间判定击中,该玩家几乎永远打不中任何人。

延迟补偿(Lag compensation)通过“时间倒流”解决了这个问题。当开火判定到达时,服务器会将所有其他玩家移回到射手开枪时他们所处的位置,然后再在那里进行命中判定。

这确实有效,但也伴随着代价。时任 Valve 开发者的扬·伯尼尔(Yahn Bernier)在他 2001 年关于延迟补偿的论文中描述道:当“一名高延迟玩家射击低延迟玩家并命中时,在低延迟玩家看来,这名高延迟玩家仿佛不可思议地‘绕着掩体拐弯开枪’击中了自己”。

低延迟玩家在自己的屏幕上已经躲到了掩体后,但回溯状态下的服务器却判定他们还没有。

各个工作室对此权衡的调校各不相同。《Apex 英雄》(APEX Legends)刻意在低 Ping 和高 Ping 玩家之间平均分摊这种“荒谬感”,接受在 300 毫秒延迟下的玩家可能会在掩体后被击中。《无畏契约》(VALORANT)估计拉出掩体观察(Peeking)的玩家大约有 141 毫秒的先手优势,并围绕缩小这一差距构建了其 Tick 率、缓冲机制和路由系统。当差距拉大时,两者都会表现为不同步和位置拉扯(Rubberbanding)。

没有任何延迟补偿设置能够彻底解决巨大的 Ping 差距。只有将差距保持在较小范围内才行,这也是为什么匹配机制必须考虑网络延迟的原因。Edgegap 的匹配系统为此包含了延迟规则,我们的通过匹配优化延迟指南详细介绍了该方法,同时探讨了电子竞技中的公平性与延迟。

什么是 Tick 率和更新率?

每个游戏服务器上都运行着两个时钟,它们经常被混为一谈。

  • Tick 率(或模拟率):服务器每秒处理输入并推进游戏世界的次数。

  • 更新率(或发送率):服务器每秒向客户端发送结果的次数。

它们通常相等,但许多游戏引擎会将二者解耦。

每个 Tick 都是一个固定的时间预算。换算方法很简单:用 1,000 除以赫兹(Hz)数即可。

Tick 率

单 Tick 耗时

示例

20 Hz

50 ms

《Apex 英雄》

~31 Hz

32 ms

《部落》(1998)

60 Hz

16.67 ms


64 Hz

15.625 ms


128 Hz

7.8125 ms

《无畏契约》

Tick 间隔会在网络延迟的基础上增加额外延迟。平均而言,玩家的输入在被服务器处理前大约需要等待半个 Tick,因此从 64 Hz 提升到 128 Hz 可将该等待时间从大约 7.8 毫秒减少到 3.9 毫秒。

如果服务器无法在时间预算内完成工作,就会发生滞后。在《Apex 英雄》中,服务器一旦错过其 50 毫秒的时间窗口,整场比赛就会出现卡顿,直到物理计算、动画和同步状态追赶上来。玩家会看到位置瞬移回扯、瞬移以及命中判定被无效化。

较低的更新率会导致更奇特的异常现象。YouTube 频道 Battle(non)sense 背后的独立分析师 Chris 在其 2017 年的“Netcode 101”视频中解释了“超级子弹”(super bullet)现象。在每秒 10 次更新的速率下,每个数据包之间相隔 100 毫秒,这与射速为每分钟 600 发的枪械发射两发子弹的间隔相同。如果一把枪的射速达到 750 RPM 或更快,就会将两颗或更多子弹塞进同一次更新中,结果受害者承受的看起来像是一次击中,但造成的伤害却超过了单发子弹的上限。

更高的 Tick 率可以减少延迟并提高命中判定的精准度。但它们也会增加每场对局消耗的 CPU 资源;如果更新率随之提高,还会消耗更多带宽。关于完整的权衡考量,请参阅游戏服务器 Tick 率详解。

游戏在何处运行?托管架构

第一个架构层面的抉择是权威模拟运行在哪里。大致有三种选择。

点对点 / P2P(玩家自建主机)。由一名玩家的设备充当主机,或者各个对等节点之间直接互联。这种方式没有服务器账单。作为交换:

  • 主机以零网络延迟进行游戏,而其他所有人都要依赖主机家庭网络的上传速度。

  • 当主机退出时,对局会终止,或者在另一名玩家接管期间暂停。请参阅 Edgegap 关于点对点或中继架构游戏中的主机迁移指南。

  • 直接连接会将每个玩家的 IP 地址暴露给对局中的其他人。

  • 权威性存在于玩家的设备上,因此该玩家可以篡改游戏状态。

中继(Relay)。中继服务器在对等节点之间转发数据包。它能够隐藏玩家的 IP 地址,并协助穿透受限的家庭网络建立连接。它不运行游戏模拟,也不验证任何内容,因此点对点架构中的权威性问题依然存在。

专用服务器(Dedicated server)。模拟运行在开发者控制的机器上。客户端发送输入,服务器决定实际发生的情况。这消除了主机优势和主机迁移问题,并为每位玩家提供了一个中立的连接点。其代价是成本和覆盖范围:必须为服务器付费,而且它们必须部署在离每位玩家足够近的地方,以保持合理的 Ping 值。

许多游戏采用混合模型。《命运2》(Destiny 2)将点对点与权威服务器结合在了一起。像 Edgegap 的游戏服务器托管这样的编排平台,其价值在于能够根据需要随时随地在每场比赛附近就近启动专用服务器,而不是在少数几个区域常驻闲置的服务器集群。关于主流网络代码库如何支持每种模型,请参阅 7 种网络代码集成方案。

如何共享游戏状态?同步模型

第二个抉择是各台设备如何保持一致。这与托管架构相互独立:下述每种方法都可以基于点对点或专用服务器运行。

帧同步 / Lockstep(输入延迟)。设备之间仅交换输入指令,每台设备都运行相同的确定性模拟。在收到该步骤中所有人的输入之前,任何人都不能向前推进。它消耗的带宽极低,并且每个屏幕上显示的内容完全一致。缺点在于输入延迟等于网络延迟,并且模拟必须在不同硬件之间具有绝对的确定性。这种方案在策略游戏中很常见。

回滚(Rollback)。每台设备都预测其他玩家的输入并立即执行模拟。当真实的输入到达且与预测不同时,游戏会倒回该帧并重新向前模拟。操作手感即时流畅,代价是偶尔会出现画面修正并占用额外的 CPU。这是格斗游戏的行业标准,它同样适用于专用服务器:例如《以太之战 2》(Rivals of Aether 2)就将回滚网络代码与 Edgegap 上的专用服务器相结合。Edgegap 的输入延迟与回滚对比及其回滚网络代码指南对两者进行了深度解析。

状态同步/复制(State replication)。服务器发送世界的快照,客户端采用四种技术来掩盖延迟:

  • 客户端预测:客户端立即应用自身的输入,即《QuakeWorld》的核心思想。

  • 服务器校准:当服务器的响应到达时,客户端校正其预测,并重新播放服务器尚未处理的任何输入。

  • 实体插值:其他玩家的渲染画面略微落后于当前时间,在收到的两个快照之间平滑过渡。

  • 延迟补偿:如前所述,服务器在判定命中时进行时间回溯。

这是射击游戏的通用标准,从《部落》到《无畏契约》皆是如此。每种技术都是在用一种异常现象换取另一种:预测会导致画面校正拉扯,插值会增加额外延迟,而延迟补偿则会导致“在掩体后被击中”的瞬间。

丢包会对游戏造成什么影响?

互联网并不保证数据包一定能送达。数据包可能因 Wi-Fi 干扰、链路拥塞、硬件故障和路由器过载而丢失。正如我们在《Apex 英雄》深度解析中指出的那样,丢包并不总是开发者的过错。

这就是为什么实时游戏使用 UDP 而不是 TCP。TCP 保证每个数据包按顺序到达,因此一旦丢失一个,后续的所有数据包都必须等待其重传。对于游戏而言,这意味着网络恢复期间角色会在移动中途僵住冻结。UDP 允许游戏自主决定什么更重要:丢失的位置更新只需直接被下一个更新替换即可。

在低更新率下,丢包造成的危害更加严重,因为每个丢失的数据包都会留下更大的空缺。游戏通常通过数据冗余来防御丢包。《部落》在连续三个数据包中发送每个玩家的输入。《守望先锋》将所有未确认的输入打包到每个数据包中,这样下一个数据包就能在服务器执行模拟之前填补任何空缺。

各个组件如何协同工作

上述每一个概念都在管理着同一个数字:从一名玩家做出动作到其他所有玩家看到该动作之间的时间间隔。

物理距离和路由决定了起点。Tick 率和更新率增加了自身固有的延迟。托管架构决定了谁来承担这种差异,而同步模型则决定了在屏幕上的视觉表现。

这就是为什么在我们深度解析的几乎所有游戏中都会遇到相同的问题。不同游戏给出的答案各异,但问题本身始终如一。

许多答案最终都归结为服务器在何时何地运行。跨越分布式网络的自动化混合编排——将用于稳定流量的裸金属服务器与用于应对峰值流量的云资源相结合——让同一种方案能够服务于截然不同的游戏类型,从大型 MMO 到每台服务器运行多个比赛房间的轻量级移动游戏。欲了解其工作原理,请深入了解 Edgegap 的游戏服务器编排解决方案。

参考来源

本文基于并引用了“参考来源”中列出的文献。原始内容的所有权利均归其各自所有者所有。

书写者

菲利普·科特 (Philip Côté) (首席技术官),雅库布·莫蒂尔 (Jakub Motyl) (产品负责人),加布里埃尔·帕伦特 (Gabriel Parent) (总监)

Get your Game Online Easily & in Minutes

立即开始集成!

轻松在线游戏
且在几分钟内