免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

面试题:游戏、直播为什么常用 UDP?KCP 是什么?为什么比 TCP 更适合低延迟场景?

面试题:游戏、直播为什么常用 UDP?KCP 是什么?为什么比 TCP 更适合低延迟场景? 面试题游戏、直播为什么常用 UDPKCP 是什么为什么比 TCP 更适合低延迟场景一、核心思路一句话实时业务核心不是“绝对可靠”而是“低延迟、及时到达”UDP负责低开销传输KCP在UDP之上补充可靠传输、快速重传、流控等能力通过增加带宽开销换取更低的丢包恢复时延。二、先回答游戏到底使用 TCP 还是 UDP标准答案不能简单说“游戏都使用 UDP”。实时对战、语音、实时互动等场景通常更关注低延迟和及时性因此常见方案是应用 │ ├── 实时状态/操作指令 │ ↓ │ UDP │ ↓ │ 自定义可靠机制 │ / KCP / 其他协议 │ └── 登录、支付、资源下载等 ↓ TCP / HTTPS原因是不同数据对“可靠性”和“实时性”的要求不同。例如玩家移动指令 100ms前的“向左移动” ↓ 现在才到 ↓ 即使可靠也已经失去实时价值所以实时业务往往遵循旧数据晚到有时不如丢掉新数据必须尽快到。但实际大型游戏通常是多协议、多通道组合并不是整个游戏只使用 UDP。三、UDP 和 TCP 的核心区别1. UDPUDP提供的是应用 ↓ UDP ↓ IP ↓ 网络UDP本身不保证一定到达按顺序到达不重复自动重传拥塞控制可靠字节流因此可以理解为UDP只负责尽可能把数据报交给IP网络不负责把“可靠传输”这件事情全部做好。2. TCPTCP在IP之上增加了大量传输控制能力TCP ├── 序列号 ├── ACK ├── 超时重传 ├── 快速重传 ├── 流量控制 ├── 拥塞控制 ├── 有序交付 └── 可靠字节流因此TCP UDP/IP之上的一整套可靠传输机制更准确地说TCP并不是简单的“UDP 可靠性”两者在传输语义和实现机制上都有明显差异。四、为什么实时业务不直接使用 TCP核心矛盾TCP追求可靠、有序、稳定实时业务追求及时。例如发送 A → B → C → D 假设B丢失 A → 到达 B → 丢失 C → 到达 D → 到达TCP必须保证应用层看到A B C D因此B没有恢复之前后面的数据可能受到队头阻塞Head-of-Line Blocking影响。对于文件下载B晚一点到 ↓ 没关系 ↓ 最终完整下载但对于游戏B 100ms之前的移动指令 现在 B终于到了 问题 玩家已经移动到下一位置了所以实时业务更关注延迟 ↓ 丢包恢复速度 ↓ 实时性而不是单纯追求100%可靠 严格有序五、KCP到底是什么这是面试最容易答错的地方。一句话KCP不是TCP、UDP之外的第三种底层传输协议而是一套可以运行在UDP等底层传输之上的可靠传输算法/协议实现。KCP官方实现本质上是轻量级算法库本身不负责真正的网络收发应用需要提供底层发送回调常见使用方式就是应用 ↓ KCP ↓ UDP ↓ IP ↓ 网络KCP官方实现明确提供了ikcp_send、ikcp_input、ikcp_update等接口并通过output回调把KCP数据交给底层网络发送。(GitHub)所以UDP 底层数据报传输 KCP 在UDP之上增加可靠传输能力六、KCP解决了UDP什么问题裸UDP发送 ↓ UDP ↓ 网络 ↓ 可能丢包KCP增加应用数据 ↓ KCP ├── 序列号 ├── ACK ├── 超时重传 ├── 快速重传 ├── 接收窗口 ├── 流量控制 └── 可配置拥塞控制 ↓ UDP ↓ 网络因此可以把KCP理解成“UDP 应用层可靠传输机制”并且针对低延迟进行了激进优化。七、KCP为什么比TCP更快这里不要回答“KCP就是TCP但是速度更快。”正确答案应该拆成几个机制。主要矛盾丢包发生以后TCP和KCP谁能更快恢复数据。KCP官方实现主要通过以下机制降低传输延迟KCP低延迟 │ ┌──────────────┼──────────────┐ ↓ ↓ ↓ 更积极的RTO 快速重传 可关闭拥塞控制 │ │ │ ↓ ↓ ↓ 更快发现丢包 不必等超时 减少主动降速八、机制一更积极的超时重传TCP的RTO并不是简单的RTO 2 × RTT标准TCP会根据SRTT RTTVAR等参数计算RTO并在重传超时后进行退避。RFC 6298规定的基础计算形式为RTO SRTT max(G, 4 × RTTVAR)并规定了相应的重传退避机制。(RFC 编辑器)KCP则提供了更激进的低延迟策略。KCP源码中可以看到IKCP_RTO_MIN 100ms IKCP_RTO_NDL 30ms快速模式可以降低最小RTO从而更早进行丢包检测。(GitHub)所以面试不要死背TCP 2倍 KCP 1.5倍而应该说KCP通过更积极的RTO和快速模式缩短丢包恢复等待时间。九、机制二快速重传这是KCP非常重要的优化点。假设发送 1 2 3 4 5网络中1 √ 2 × 3 √ 4 √ 5 √接收端可能继续反馈后面的ACK。发送端发现ACK 1 ACK 3 ACK 4 ACK 5那么可以推断2可能丢失KCP可以根据配置的快速重传阈值提前重传2而不是一直等待RTO超时。KCP的ikcp_nodelay( kcp, nodelay, interval, resend, nc )中resend就是快速重传相关配置。官方实现支持例如resend 2即出现一定数量的ACK跳跃后直接触发快速重传。(GitHub)十、机制三选择性重传核心思想只重传真正丢失的数据例如发送 1 2 3 4 5 实际 1 √ 2 × 3 √ 4 √ 5 √恢复时TCP传统机制 → 根据具体实现和协议状态进行重传控制 KCP → 针对丢失的数据段进行选择性重传所以KCP可以减少不必要的数据重复发送。十一、机制四拥塞控制可以配置KCP并不是“天然没有拥塞控制”。官方实现存在nc参数nc 0表示正常拥塞控制。nc 1表示关闭传统拥塞控制。例如ikcp_nodelay(kcp, 1, 10, 2, 1);可以配置nodelay 1 interval 10ms resend 2 nc 1即低延迟 快速重传 关闭拥塞控制官方文档也明确说明KCP可以通过配置牺牲一定公平性和带宽利用率来换取更低延迟。(GitHub)十二、为什么关闭拥塞控制会更快正常情况下网络拥塞 ↓ 丢包 ↓ 判断网络可能拥塞 ↓ 降低发送速度这样做的好处保护网络 提高公平性但实时游戏可能更关注当前操作必须尽快送达因此某些场景可以选择减少拥塞退让 ↓ 保持较高发送速率 ↓ 降低延迟代价更高带宽 更低网络公平性 可能加剧拥塞所以KCP的“快”不是凭空产生的而是用带宽、网络公平性和部分拥塞控制能力换来的。十三、KCP的完整工作流程这是面试时最值得画出来的结构图。应用层 │ │ ikcp_send() ↓ ┌───────────────┐ │ KCP │ │ │ │ 序列号 │ │ ACK │ │ RTO │ │ 快速重传 │ │ 选择性重传 │ │ 流控 │ │ 拥塞控制 │ └───────┬───────┘ │ output回调 ↓ UDP ↓ IP ↓ Internet ↓ UDP ↓ ┌───────────────┐ │ KCP │ │ │ │ ikcp_input() │ │ ACK处理 │ │ 丢包检测 │ │ 重排 │ └───────┬───────┘ ↓ 应用层 ikcp_recv()KCP官方使用方式就是ikcp_send() ↓ KCP内部缓存 ↓ ikcp_update() ↓ output() ↓ UDP发送收到UDP数据后UDP receive ↓ ikcp_input() ↓ KCP处理ACK / DATA ↓ ikcp_recv()(GitHub)十四、KCP为什么需要 ikcp_update()这是深入理解KCP很重要的一点。ikcp_send()不等于立即完成整个网络发送和重传管理。KCP内部需要周期性执行ikcp_update(now)它负责推动KCP状态机当前时间 ↓ 检查ACK ↓ 检查超时 ↓ 检查需要重传的数据 ↓ 发送ACK ↓ 执行重传 ↓ 调用output()所以实际结构类似应用发送数据 ↓ ikcp_send() ↓ 进入KCP发送队列 ↓ ikcp_update() ↓ KCP决定什么时候真正发送 ↓ output() ↓ UDP这也是理解KCP源码的关键入口。十五、KCP有哪些核心数据结构如果面试官继续追源码可以继续往下说ikcpcb │ ├── snd_queue │ ↓ │ 等待发送的数据 │ ├── snd_buf │ ↓ │ 已经发送但尚未确认的数据 │ ├── rcv_buf │ ↓ │ 已收到但可能乱序的数据 │ ├── rcv_queue │ ↓ │ 已经可以交给应用的数据 │ ├── acklist │ ↓ │ 等待发送的ACK │ ├── snd_wnd │ ↓ │ 发送窗口 │ ├── rcv_wnd │ ↓ │ 接收窗口 │ ├── rx_srtt │ ↓ │ 平滑RTT │ ├── rx_rto │ ↓ │ 重传超时 │ └── fastresend ↓ 快速重传阈值这部分比单纯说“UDP可靠性”更接近源码层面。十六、KCP的代价是什么不能只回答“KCP更快”。核心是低延迟 ↕ 带宽 / 公平性 / 网络压力KCP官方资料给出的设计目标就是以额外带宽开销换取更低传输延迟官方README描述其典型额外带宽开销约为10%20%并强调这是具体实现和配置下的性能取舍而不是固定保证值。(GitHub)因此TCP ↓ 更强调可靠性、拥塞控制、公平性 KCP ↓ 可以更激进地追求低延迟 代价 ↓ 更多带宽 更多协议状态 更复杂的应用层实现十七、UDP丢包严重怎么办方案一改善底层网络 方案二应用层增加冗余方案一优化网络链路例如普通公网 ↓ 专线 / SD-WAN / 软件组网 / 多线路 ↓ 改善跨地域网络质量注意不能简单说“国内运营商会优先丢UDP”。真实网络行为取决于运营商 网络设备 拥塞情况 QoS策略 NAT 防火墙 线路 地区 网络协议因此更准确的面试表达是UDP没有TCP那种面向连接的传输保证在部分网络环境下可能面临更明显的丢包、NAT穿透或QoS差异问题KCP只能解决传输层以上的可靠传输无法从根本上修复底层链路质量。十八、方案二前向纠错 FECFECForward Error Correction前向纠错。核心思想原始数据 A B C D ↓ 额外生成冗余数据 P Q ↓ 一起发送 A B C D P Q即使部分数据丢失A √ B √ C × D √ P √ Q ×接收端仍可能利用A B D P恢复C这样就可以丢包 ↓ 不一定等待重传 ↓ 直接利用冗余恢复这对于实时音视频 实时游戏 高丢包网络特别有价值。十九、FEC和KCP是什么关系不能简单说UDP ↓ FEC ↓ KCP因为FEC不是KCP的核心组成部分。更准确的架构可以是应用 ↓ KCP ↓ FEC ↓ UDP或者应用 ↓ FEC 自定义可靠传输 ↓ UDP具体取决于协议栈设计。两者解决的问题不同KCP → 丢包后重新发送 FEC → 丢包后利用冗余直接恢复二十、KCP FEC为什么可以降低实时延迟传统可靠机制数据丢失 ↓ 等待ACK ↓ 判断丢包 ↓ 重传 ↓ 等待再次到达FEC数据丢失 ↓ 已有冗余 ↓ 直接恢复因此KCP 解决 可靠传输 FEC 解决 减少重传等待组合后UDP ↓ FEC ↓ KCP ↓ 应用在高丢包场景下可以降低单纯依赖重传造成的延迟。但代价是冗余数据 ↓ 额外带宽所以本质仍然是用带宽换延迟。二十一、为什么不能把KCP理解成“比TCP快30%40%”面试中最好不要把KCP比TCP快30%40%当成绝对结论。因为实际性能取决于RTT 丢包率 带宽 拥塞 窗口 MTU KCP参数 TCP实现 操作系统 网络路径 业务数据量KCP官方README确实给出了30%40%平均传输速度改善的设计/测试描述但这是特定测试和配置下的数据不代表所有网络环境都固定快30%40%。(GitHub)面试应该说KCP通过更积极的丢包恢复、快速重传、可配置的拥塞控制等机制在特定网络和配置下可以降低传输延迟但不是所有场景都必然比TCP快。二十二、主要矛盾和次要矛盾主要矛盾可靠性 VS 实时性TCP更偏向 可靠 有序UDP更偏向 低开销 实时性KCPUDP基础 可靠传输 低延迟优化次要矛盾带宽 VS 延迟 网络公平性 VS 低延迟 重传 VS FEC冗余 公网质量 VS 应用层优化二十三、面试最容易被追问的几个问题Q1KCP是TCP吗不是。TCP → 操作系统实现的传输层协议 KCP → 应用层实现的可靠传输协议/算法 通常运行在UDP之上Q2KCP是UDP吗也不是。UDP → 底层传输协议 KCP → UDP之上的可靠传输机制Q3KCP为什么比UDP可靠因为它自己实现序列号 ACK 超时重传 快速重传 窗口 有序组装Q4KCP为什么比TCP快不要回答“因为UDP比TCP快。”这是错误的。正确回答KCP利用UDP作为底层数据报传输在应用层重新实现可靠传输并通过更积极的RTO、快速重传、选择性重传以及可配置拥塞控制等方式降低丢包恢复延迟。Q5KCP是不是没有拥塞控制不是。KCP有拥塞控制并且可以通过配置关闭传统拥塞控制。(GitHub)Q6KCP能解决网络丢包吗只能解决一部分。KCP ↓ 可以 发现丢包 重传丢包 降低恢复时间 不能 改变物理链路质量 增加运营商带宽 消除严重网络拥塞 保证UDP一定不被丢弃二十四、最终满分答案游戏、实时互动等业务并不是简单地“只使用UDP”而是通常会根据数据类型选择不同的传输方式。实时状态和操作指令更关注低延迟因此常采用UDP以及UDP之上的自定义可靠传输机制登录、支付、资源下载等对完整性要求更高的业务则可以使用TCP或HTTPS。UDP本身不保证可靠、有序和重传KCP就是在UDP等底层传输之上实现的一套可靠传输算法通过序列号、ACK、超时重传、快速重传、选择性重传、窗口控制等机制补足可靠性。KCP的核心优势不是“UDP天然比TCP快”而是它可以针对低延迟场景进行更激进的优化例如缩短丢包检测和恢复时间、支持快速重传并允许配置拥塞控制策略。代价是额外的带宽开销以及更低的网络公平性。如果网络丢包严重还可以结合FEC通过冗余数据直接恢复部分丢失的数据减少等待重传造成的延迟。所以整个技术取舍可以概括为TCP ↓ 可靠、有序、公平 ↓ 更适合通用可靠传输 UDP ↓ 低开销、低延迟、无内建可靠保证 ↓ 适合实时业务的底层传输 KCP ↓ UDP 应用层可靠传输 ↓ 更积极的丢包恢复 ↓ 用带宽和复杂度换低延迟 FEC ↓ 用冗余数据直接恢复部分丢包 ↓ 进一步减少重传等待最终本质就是实时业务不是不要可靠性而是把“可靠性”从TCP的固定机制变成可以由业务根据实时性、带宽、丢包率进行定制的机制。记忆时只抓住 5 个词UDP打底 → KCP可靠 → 快速重传 → 可控拥塞 → FEC抗丢包这 5 个词基本就能把整道题的主线讲出来。
返回列表