笃行
首页
个人 & 心法
互联网/硬件后台
游戏基础架构
UE 引擎
游戏业务
AI / 大模型
数据结构与算法
机器学习数学
通用基础
GitHub
首页
个人 & 心法
互联网/硬件后台
游戏基础架构
UE 引擎
游戏业务
AI / 大模型
数据结构与算法
机器学习数学
通用基础
GitHub
  • 接入与通信

    • 游戏基础架构与工具
    • 接入网关(长连接接入层)
    • 消息总线(共享内存 IPC)
    • 帧同步(Lockstep)
    • 全栈极限低延迟(物理层→应用层)
    • KCP 与 QUIC
  • 网络与服务网格

    • CNI 与 K8s 网络插件
    • 容器运行时:Docker 与 containerd
    • Istio 与 Cilium 服务网格
    • 服务网格:中心化 vs 去中心化
    • eBPF 原理与在网络/可观测/安全的落地
    • 自研 Mesh 服务网格 × K8s 部署
    • 自研 Mesh × K8s · 数据面深水区
    • Tco 协程框架 · 运行时深水区
    • K8s 异构 & 网络插件
  • 有状态服务

    • 分布式游戏存储(分布式 KV)
    • 有状态服务的数据迁移
    • 有状态服务的数据恢复与容灾
    • 有状态服务的 K8s 编排层治理(防漂移 + 节点崩溃恢复)
    • 内存配置热刷新与更新机制
  • 算法与协程

    • 一致性哈希四算法实现(Ring Hash / Ketama / Maglev / Jump Hash)
    • 蓄水池抽样(Reservoir Sampling)与加权扩展
    • C++ 协程:有栈 vs 无栈 vs C++20 原生(函数染色与 libco)
    • Raft 与 Gossip:CP 强一致共识 vs AP 最终一致传播
  • 流量与承载

    • 游戏秒杀场景承载
    • 令牌桶与漏桶
    • 限流与熔断
    • 限流:互联网 vs 游戏
    • 灰度发布 · Canary / BlueGreen / A-B / Shadow
    • 服务器日常系统开发与维护 SOP
    • 极限发压工具设计(多长连接 + 发压任务)
    • 性能分析与优化方法论(六条排查线)
  • 编译与排查

    • 编译优化与 LLVM/Clang/GCC
    • Sanitizer 工具链与内存泄漏定位

全栈极限低延迟(物理层 → 应用层)

游戏侧端到端延迟预算 · DNS/Anycast 就近 · OSPF/ECMP 多路径 · LVS 四层 · kernel-bypass · 帧预算硬约束

一句话结论

延迟不是"越低越好"的加分项,而是帧预算里的硬约束:60fps 只有 16.6ms,链路上每一跳都在花这笔钱。极限低延迟 = 自顶向下逐跳砍——就近选路(Anycast)→ 等价多路径(OSPF/ECMP)→ 四层直连(LVS DR)→ 绕过内核(io_uring/DPDK/RDMA)→ 单线程无锁,每一层都用"省掉哪次跳/切换/拷贝"换代价。

场景问题

打个比方:一款 FPS 每帧只有 16.6ms(60fps) 的预算,像一张限时地铁票——从你按下开火键,到服务器裁决、再把结果甩回你屏幕,这一整趟必须在票面时间内跑完,超时这一帧就"废票"(画面回滚、命中判定飘、手感发粘)。链路上每一跳都在花这张票的钱:DNS 多问一次远程递归、绕了个大圈的骨干路由、四层负载多改一次 IP、内核协议栈多拷一次内存、应用线程被一次锁或一次 GC 卡住……每一笔都从 16.6ms 里扣。极限低延迟,就是把这趟地铁的每一段都换成直达、少换乘、免安检。类比失效边界:地铁票可以"晚点补偿",但实时对战的这一帧过期就是过期——尾延迟(P99/P999)比平均延迟重要得多,一次 50ms 的抖动就是一次可感知的卡顿。所以下面每一层,我们关心的都是"最坏情况能压到多少",而不是"平均看起来还行"。

实时对战(FPS / MOBA / 格斗)后台是典型的计算密集 + 强状态 + 单帧预算场景,与互联网后台(I/O 密集、无状态、吞吐优先)根本不同(详见 游戏 vs 互联网后台)。端到端一趟要经过的跳:

把 16.6ms 拆成一张"每跳花多少"的预算表(数量级、方向性对比,非某环境实测):

关于数字

下表所有耗时均为业界公开资料的数量级(μs/ms),强依赖网卡、内核版本、拓扑与负载,不是本环境实测,仅用于建立"哪一跳值得砍、砍了省多少"的方向感。绝对值请以自己的压测为准。

跳环节典型量级极限手段砍到主要代价
①客户端→入口选路(首包/解析)DNS 首次解析 ~10–100ms;之后走已建连接GeoDNS/Anycast 就近,长连接复用免重解析会话漂移、缓存 TTL
②骨干+机房路由 RTT同城 ~1–5ms,跨区 ~30–100ms+就近入口 + ECMP 无阻塞,物理上缩短距离机房/边缘建设成本
③④四层负载转发每包 ~亚 μs–数 μsLVS DR 只改 MAC、响应直连绕过 LB同二层网段约束
⑤主机内核协议栈单程~数 μs–数十 μs(含中断/拷贝/软中断)io_uring 减 syscall;DPDK/XDP 绕栈到亚 μs;RDMA 绕 CPU独占核/专用网卡/难调试
⑥应用处理 + 回包取决于逻辑与调度单线程无锁、批量 syscall、关 Nagle编程复杂度

下面自顶向下,一层一层讲"极限手段 + 为什么这么选 + 代价"。

实现方案

① 接入寻址层:DNS 就近 + Anycast

目标:让玩家的第一个包就打到物理上最近的入口,别绕地球。

  • GeoDNS / EDNS Client Subnet(ECS):权威 DNS 按解析请求的来源地域返回最近入口 IP。传统 DNS 只看递归解析器的 IP(可能离用户很远),ECS 把客户端子网带给权威,让"就近"判断更准。
  • Anycast:同一个 IP 在多地入口同时宣告(BGP),路由系统天然把玩家引到"BGP 意义上最近"的那个入口。客户端无感知——它以为只连了一个 IP,实际连到了最近的边缘。

打个比方:GeoDNS 是报路名的总台——你打客服电话报出所在城市,总台告诉你"最近的门店地址是 XX"(返回一个就近 IP);Anycast 则是连锁店统一用一个电话号码,你拨过去,运营商的交换网络自动把你接到离你最近的那家分店,你根本不知道接的是哪家。类比失效边界:连锁店统一号码在"打一通就挂"的场景很爽,但游戏是长连接——万一通话中你移动了、或某条骨干链路抖动导致 BGP 重新收敛,Anycast 可能把你的后续包路由到另一家分店(另一台入口),而那台并不认识你的会话,连接就断了。这就是 Anycast 会话漂移。

Anycast 与游戏长连接的取舍:Anycast 对无状态、短交互(DNS 本身、HTTP/CDN、QUIC 首包)近乎完美;但对有状态长连接要谨慎——路由收敛可能让同一条流漂到不同入口。常见折中:用 GeoDNS/Anycast 只做"就近选入口",一旦选定就用 Unicast 地址建立并固定长连接,或在入口层做会话保持 / 连接迁移(QUIC 的 Connection ID 迁移思路)。

为什么实时对战偏 UDP + 自研可靠层,而非纯 TCP:

维度TCPUDP + 自研可靠层(KCP / QUIC 思路)
丢包处理严格按序 → 队头阻塞:一个包丢了,后面到了的也得等选择性重传,无队头阻塞;过期的状态帧干脆丢掉不重传
重传时机由内核拥塞控制决定,偏保守应用可激进重传(更小 RTO、快速重传),拿带宽换延迟
拥塞控制面向吞吐(CUBIC/BBR,详见 tcp-net)面向尾延迟,可为对战定制
连接迁移四元组绑定,换网就断QUIC 用 Connection ID,切 Wi-Fi/4G 不断连

结论:能容忍旧状态丢弃、要求低尾延迟的实时同步走 UDP + 可靠层;必须可靠有序的登录/交易/聊天走 TCP。帧同步的确定性与重传细节详见 帧同步 lockstep。

② 网络路由层:OSPF 与 ECMP

选好了入口,接下来是"入口到机房、机房内部到具体机器"这段路由要又快又不堵。

  • OSPF(开放最短路径优先):链路状态路由协议——每台路由器泛洪自己的链路状态(LSA),各自算出全网拓扑图,再用 Dijkstra/SPF 算到各目的地的最短路径。相比距离矢量(RIP),它收敛快、无环、支持大规模区域划分。骨干互联更多用 BGP(Anycast 就靠它),机房/AS 内部用 OSPF。
  • ECMP(等价多路径):当到同一目的地存在多条等价路径时,按流哈希(五元组)把不同的流散到多条链路上,既做负载均衡又做冗余。关键点:哈希以流为单位,保证同一条 TCP/UDP 流始终走同一条路(否则乱序/重排),单条链路挂了其余立即接管。
  • 机房内 Leaf-Spine(叶脊)无阻塞组网:任意两台服务器之间跳数固定(都是 leaf→spine→leaf),配合 ECMP 做到东西向无阻塞,避免传统三层树形的汇聚层瓶颈。

打个比方:OSPF 像全城司机人手一份实时路况地图,各自算最短路线,出了事故(链路挂)大家几秒内同步更新重算;ECMP 则是一条主干道并排开了 4 条车道,收费站按车牌尾号(流哈希)把车分到不同车道,既不堵、塌一条还剩三条。类比失效边界:ECMP 的"按车牌分车道"是无状态哈希——一旦链路数量变化(加/减一条),哈希结果重新分布,部分流会被重新分到新链路,长连接可能瞬间乱序或重路由。所以变更链路要挑低峰、用一致性哈希类算法(如 Maglev)减少重分布,别在开黑高峰动骨干。

职责边界一句话:Anycast/BGP 解决"跨 AS 去哪个入口",OSPF 解决"AS 内部怎么走最短",ECMP 解决"多条等价路怎么分摊+冗余"。三者分工,别混为一谈。

③④ 负载均衡层:LVS DR 四层直连

流量到了机房,要均分给一排接入机,且这一步本身不能成为瓶颈。这里用 LVS(内核 IPVS)四层负载,工作在 IP+端口,不解析应用层。

  • 为什么用 DR 模式:Director 只改目的 MAC(二层转发),响应包由 Real Server 直接回客户端、完全不经过 Director。而游戏流量下行(状态广播)远大于上行,DR 让 Director 只承担最小的入向流量,吞吐最高、延迟最省。
  • 保连接:用 Maglev / 一致性哈希做调度,机器增减时尽量不打断已有连接(对长连接尤其关键)。

LVS 三种转发模式(NAT/DR/TUN)的完整对比、DR 对 Real Server 的 ARP 抑制配置(arp_ignore/arp_announce)、调度算法与 Keepalived VRRP 高可用,是 LVS 与 epoll 的单一事实源,本篇不重复展开。这里只强调它在低延迟链路中的位置:四层直连,绕过七层网关的解析/缓冲开销,把"均分连接"这步的成本压到"每包改一次 MAC"。

为什么不直接用七层网关接入:七层要完整解析应用层、维护双向连接、缓冲请求体,单机吞吐有限、延迟更高。低延迟入口的正确分层是:LVS 四层廉价均分连接 → 接入网关(access-gateway)管长连接/私有协议/会话。

⑤ 主机内核层(极限重点):减少内核态/用户态切换

包进了网卡到被应用读到,中间要过:网卡中断 → 软中断 → 内核协议栈 → socket 缓冲 → 拷贝到用户态 → 唤醒线程。每一步都在花钱。极限低延迟的主战场就在这里:能省一次上下文切换、一次内存拷贝、一次中断,就省一笔。

一张"代价递减"的阶梯图——越往下,省掉的东西越多,代价(通用性/CPU/硬件/可维护性)也越大:

逐级"省掉了什么 / 代价是什么":

技术省掉了代价什么场景才上
epollselect/poll 的全量拷贝+遍历(O(n)→O(1))无(早已是默认)所有高并发长连接接入,默认选择
io_uring每个 IO 一次 syscall 的开销;可批量提交/收割内核版本要求、编程模型复杂、早期版本有坑syscall 频繁成为瓶颈时(高 QPS 小包)
XDP / AF_XDP大部分内核协议栈处理(在驱动层就分流/丢弃/转发)只能做有限处理,复杂逻辑仍要回内核/用户态DDoS 过滤、四层转发、快路径分流
DPDK全部 syscall + 中断 + 内核协议栈(轮询代替中断)独占 CPU 核忙轮询(跑满 100%)、需自建用户态协议栈、难调试超高包速率、延迟极敏感的专用转发/网关
RDMA / RoCE内核 + CPU 参与数据搬运(网卡直接读写远端内存)需专用网卡(RoCE/InfiniBand)、组网复杂、成本高机内/机架内超低延迟、AI 训练、存储

打个比方:这条阶梯就像过关的方式。read/write 是每次出入境都老实排队过海关(syscall + 拷贝 + 可能睡眠);epoll 是海关给你发了张"有你的货才叫号"的登记卡(不用瞎排);io_uring 是办了快速通道,一次能提交/领取一沓包裹(批量、减少往返);DPDK 干脆包了架私人飞机直飞,不走海关也不走公共航线(全用户态轮询、绕过内核)——爽是爽,但飞机得一直烧油待命(独占 CPU 核忙轮询);RDMA 是两栋楼之间架了条传送带,货直接从你仓库送到对方仓库,连搬运工(CPU)都不用(网卡直读远端内存)。类比失效边界:私人飞机和传送带只在"运货量极大且分秒必争"时才划算——小打小闹还这么搞,就是为了省几微秒烧掉一整个 CPU 核 / 买一堆专用网卡,绝大多数业务 epoll(必要时 io_uring)就够了。

配套的"内核层调优工具箱"(不换 API,也能榨延迟):

  • 零拷贝:sendfile/splice/mmap/MSG_ZEROCOPY,减少内核态↔用户态的内存拷贝。详解见 tcp-net 与 os-zerocopy,本篇不重复。
  • NAPI:高负载时网卡从"每包一次中断"切换为"中断+轮询"批量收包,避免中断风暴。
  • busy-poll(忙轮询):应用主动轮询网卡队列,不睡眠等中断——用 CPU 换延迟,砍掉唤醒时延。
  • RSS / RPS / RFS 多队列 + CPU 亲和:网卡多队列(RSS 硬件哈希)把不同流分到不同队列/CPU,RPS/RFS 是软件版;配合把处理该流的软中断、应用线程绑到同一个 CPU 核,让数据留在同一颗核的 L1/L2 cache,避免跨核搬运。
  • IRQ 绑核:把网卡中断固定到专用核,别和应用线程抢。
  • NUMA 就近:网卡挂在哪个 NUMA node,处理它的核和内存就用那个 node 的,避免跨 NUMA 访问的高延迟。
  • HugePage 大页:减少 TLB miss(DPDK 几乎必配)。

XDP/eBPF 在内核态数据面做快路径处理、为什么优于 iptables,是 eBPF 的单一事实源;容器场景下的 RSS/多队列与 CNI 数据面见 CNI 与 K8s 网络。本篇只把它们放进"减少切换"的谱系里定位。

⑥ 应用层:单线程无锁 + 批量 syscall

数据终于到了应用线程,最后一段预算在这里花:

  • 单线程无锁 Reactor:游戏逻辑服常用单线程按帧驱动——无锁、无竞争、缓存友好、行为确定,天然适合帧预算模型(这正是游戏 vs 互联网的核心差异之一,详见 game-vs-internet、并发模型 concurrency)。
  • 批量 syscall:sendmmsg/recvmmsg 一次系统调用收发多个UDP 包,把"每包一次 syscall"摊薄——小包高频场景收益巨大。
  • 关掉 Nagle / 延迟 ACK:TCP_NODELAY 关闭 Nagle,别为了攒大包而把小的操作包压着不发;注意 Nagle 与延迟 ACK 组合会互相等待造成 ~40ms 卡顿(详见 tcp-net)。
  • 时间轮定时器:海量连接的超时/心跳用时间轮(O(1) 添加/过期),别用每个连接一个定时器堆。
  • 内存池 / 对象池:预分配、复用,避免热路径上 malloc/GC 抖动破坏尾延迟(GC 对延迟的影响见 gc-stw)。

收束到帧预算:把 16.6ms 显式切成"收包+解析 / 逻辑裁决 / 状态广播打包+发送"几段,每段设预算与埋点,超预算的帧告警——这样"低延迟"才是可度量、可守护的工程约束,而不是口号。

为什么这么做

  • 为什么自顶向下逐跳砍,而不是只盯一个点:端到端延迟是每一跳之和,且瓶颈会转移——你把内核压到亚 μs,跨区 RTT 的 80ms 一样毁掉体验。所以先用延迟预算表定位"哪一跳占大头、砍它性价比最高",再逐层下手,而不是一上来就上 DPDK。物理距离(就近选路)通常是最大且最难用软件补救的一笔,所以 Anycast/GeoDNS 放在最前。
  • 为什么每层的主旋律都是"就近 / 直连 / 绕过":延迟的本质是"多走的路 + 多做的事"。就近(Anycast)砍物理距离,直连(LVS DR、四层绕七层)砍中转,绕过(kernel-bypass)砍无谓的切换与拷贝——三招都在做同一件事:删掉不必要的那一跳。
  • 为什么实时同步用 UDP + 可靠层:游戏状态帧是可丢弃的——旧位置过期了重传它毫无意义,反而占着队头让新帧也进不来(TCP 队头阻塞)。UDP + 选择性重传让"该丢的丢、该补的快补",把控制权交给最懂业务语义的应用层。
  • 为什么 kernel-bypass 要做成"阶梯"而不是"一步到位":省延迟和付代价严格正相关。epoll/io_uring 几乎零额外成本就能吃到大部分收益;DPDK/RDMA 是"用一个 CPU 核 / 一块专用网卡换几微秒"的重武器。先爬阶梯的低层,够用就停,这是工程理性而非技术炫技。
  • 为什么应用层坚持单线程无锁:游戏是强状态 + 计算密集,多线程加锁的竞争、缓存失效、不确定调度恰恰破坏尾延迟与可复现性;单线程按帧驱动无锁无竞争、缓存友好、行为确定,天然贴合帧预算。

踩过什么坑 / 怎么填的

  • Anycast 会话漂移:路由收敛把长连接漂到另一入口→连接断。填:Anycast/GeoDNS 只做就近选入口,选定后用 Unicast 固定长连接;或在入口做会话保持/连接迁移(QUIC Connection ID)。
  • ECMP 变更引发乱序:增减等价链路使流哈希重分布→长连接乱序/重路由。填:用一致性哈希类调度(Maglev)减少重分布,链路变更挑低峰。
  • DPDK 独占核的运维成本:为省几 μs 让一个核 100% 忙轮询,机器成本与散热飙升,还得自建用户态协议栈、难调试。填:先问"epoll/io_uring 够不够",只有超高包速率/极敏感场景才上 DPDK;能用 XDP 快路径解决的(如丢包过滤)别上全套 DPDK。
  • busy-poll 烧 CPU:忙轮询把核跑满,功耗与成本上去,低负载时纯浪费。填:只在延迟敏感的专用核开,或用自适应轮询(有包轮询、空闲短暂让出)。
  • NUMA 跨节点抖动:网卡在 node0、线程被调度到 node1,跨 NUMA 访问延迟翻倍且抖动。填:网卡中断、处理线程、内存分配全绑到网卡所在 NUMA node。
  • TCP_NODELAY 与延迟 ACK 组合坑:一端 Nagle 攒包、一端延迟 ACK 等待,互相干等出现 ~40ms 停顿。填:交互式小包关 Nagle;理解组合成因(详见 tcp-net)。
  • 只看平均延迟:平均 5ms 很漂亮,但 P999 有 80ms 抖动,玩家照样骂卡。填:以 P99/P999 尾延迟为核心指标,压测和告警都盯尾部。

为什么别的选择不行

  • 纯 TCP 跑实时对战:队头阻塞 + 内核拥塞控制偏保守,一个丢包拖累后续所有帧;且四元组绑定换网即断。对"可丢旧状态、要低尾延迟"的同步是错配——所以走 UDP + 自研可靠层。
  • 无脑给长连接上 Anycast:路由收敛会话漂移导致断连;正确做法是 Anycast/GeoDNS 只做就近选入口,选定后 Unicast 固定长连接。
  • 一上来就 DPDK / RDMA:为省几 μs 独占 CPU 核忙轮询、买专用网卡、自建用户态协议栈、难调试,绝大多数业务性价比极差。先爬 epoll → io_uring 阶梯,够用就停。
  • 七层网关直接接入:完整解析应用层 + 双向连接 + 缓冲请求体,单机吞吐低、延迟高,扛不住超大流量入口。正确分层是 LVS 四层廉价均分 + 接入网关管会话。
  • 多线程加锁的应用层:锁竞争、缓存失效、不确定调度破坏尾延迟与可复现性,与游戏强状态 + 帧预算相冲。单线程无锁按帧驱动才是正解。
  • 只优化平均延迟:平均漂亮但 P999 抖动照样让玩家骂卡;实时对战必须以尾延迟(P99/P999)为核心指标。

游戏 vs 互联网:低延迟选型差异

维度互联网后台游戏实时后台
核心指标吞吐 / QPS,平均延迟尾延迟 P99/P999,帧预算
状态多为无状态,可任意负载均衡强状态长连接,会话粘连、连接迁移敏感
传输层TCP/HTTP 为主UDP + 自研可靠层为主(可丢旧状态、无队头阻塞)
并发模型多线程/协程池吃 I/O 并发单线程无锁按帧驱动,计算密集
极限手段动机提吞吐、降成本守住每一帧的最坏延迟
Anycast/ECMP无脑用(无状态友好)谨慎用(长连接怕漂移/乱序)

一句话:互联网优化"平均能扛多少",游戏优化"最坏这一帧能不能按时交付"。方向不同,选型自然不同。

沉淀结论

极限低延迟不是"把每层都上最猛的技术",而是自顶向下按延迟预算做取舍:先定位占大头的那一跳,再用"就近 / 直连 / 绕过"三招逐层删掉不必要的路与切换,且够用就停——epoll/io_uring 解决 90% 的问题,DPDK/RDMA 只留给真正分秒必争的专用场景。核心指标始终是尾延迟 P99/P999 与帧预算达标率,而非好看的平均值。

性能数据(记几个数量级,面试够用)

均为业界公开量级,强依赖环境,非实测。

  • 同城机房 RTT ~1–5ms,跨区 ~30–100ms+;物理距离是最大且最难软件补救的一笔。
  • 内核协议栈单程处理 ~数 μs–数十 μs 量级;DPDK 忙轮询可把收包降到亚 μs 量级,代价是独占核。
  • LVS DR 每包转发 ~亚 μs–数 μs(只改 MAC);60fps 帧预算 = 16.6ms,30fps = 33ms。
  • Nagle × 延迟 ACK 组合坑可造成 ~40ms 停顿——交互式小包务必 TCP_NODELAY。

记忆口诀

全栈六跳:DNS/Anycast就近 → OSPF/ECMP多路径 → LVS DR四层直连 → 内核kernel-bypass → 单线程无锁 → 回包下行大
三招心法:就近(砍物理距离) / 直连(砍中转) / 绕过(砍切换与拷贝),且够用就停
路由分工:BGP去哪个入口 / OSPF内部走最短 / ECMP多路等价分摊+冗余
减切换阶梯:read/write→epoll→io_uring→XDP→DPDK→RDMA(越往下省越多,代价越大)
类比:syscall过海关 / io_uring快速通道 / DPDK包机直飞(烧一个核) / RDMA传送带(连CPU都不用)
红线:看P99/P999尾延迟,别只看平均;长连接慎用Anycast(会话漂移)

关联专题

  • LVS 与 epoll:四层负载三模式 / epoll 事件模型(本篇 LVS DR、epoll 的单一事实源)
  • TCP/网络编程 tcp-net:拥塞控制 / IO 多路复用 / 零拷贝 / Nagle 与延迟 ACK 详解
  • eBPF:XDP 内核态数据面、为何优于 iptables
  • CNI 与 K8s 网络:容器网络数据面、多队列
  • 接入网关 access-gateway:长连接接入层、私有协议、会话管理
  • 帧同步 lockstep:确定性同步、UDP 可靠层与重传
  • 游戏 vs 互联网后台 game-vs-internet:本质差异
  • UE:NetDriver / Channel / Bunch:引擎内 UDP 之上的自建可靠层(Bunch/ACK/带宽配额),本篇内核侧优化的上一层
  • perf-analysis-optimization:作为性能分析主叙事的入口——本篇讲极限低延迟的全栈砍法,perf-analysis-optimization 讲六条排查线的方法论,从中的"网络排查线"回到本篇打透。
最近更新: 2026/9/10 11:38
Prev
帧同步(Lockstep)
Next
KCP 与 QUIC