Lazy loaded image
计网丨TCP 与 UDP 核心差异及 RPC 通信选型
字数 3468阅读时长≈ 9 分钟
2025-10-12
type
Post
status
Published
date
Oct 12, 2025
slug
network2
summary
tags
技术探索
category
icon
password
导语:从“八股背诵”到“架构视野”
“既然 TCP 这么可靠,为什么音视频通话宁可丢帧也不用 TCP?”“在微服务 RPC 框架(如 Dubbo / gRPC)中,底层通信为何极度依赖 TCP?由此带来的‘粘包/拆包’问题在源码层是如何解决的?”
单纯的理论背诵很难展现技术深度。本文从传输层底层机制出发,深入剖析 TCP 与 UDP 的核心差异,并结合在 Apache dubbo-go 开源项目中的网络编解码实践,探讨分布式 RPC 选型 TCP 的必然性与权衡,最后延伸至基于 UDP 的 QUIC/HTTP/3 演进,帮助你在面试与实际架构设计中建立全局视野。

一、核心理论:TCP 与 UDP 深度对比

传输控制协议(TCP)与用户数据报协议(UDP)作为传输层的两大基石,其设计哲学代表了两种截然不同的权衡路线:强保障的管道抽象 vs 极致轻量的报文通道。

1. 连接性(Connection-oriented vs Connectionless)

  • TCP:面向连接。传输前必须经历“三次握手”协商初始序列号(ISN)、窗口缩放因子与 MSS,并在端系统内核维护复杂的 TCP 状态机(如 ESTABLISHED、TIME_WAIT 等);传输结束后通过“四次挥手”拆除连接。
  • UDP:无连接。发送端随时根据目标 IP 与端口直接构造报文发送,内核无需维护连接状态表,也没有建连导致的 RTT 时延。

2. 可靠性(Reliability & QoS)

  • TCP:提供百分之百可靠、按序、无差错、无重复的交付保障。
  • 确认应答与重传(ARQ):每个字节都有序列号(Sequence Number),接收方回复 ACK;超时或连续收到 3 次重复 ACK 触发快速重传。
  • 流量控制(Flow Control):通过滑动窗口(Receive Window)动态调节发送速率,避免打垮接收端缓冲区。
  • 拥塞控制(Congestion Control):通过慢启动、拥塞避免、快重传、快恢复算法(如 Cubic、BBR)感知网络拥塞并主动退避。
  • UDP:尽力而为(Best-effort)。不保证送达、不保证顺序、不保证不重复,也没有任何内置的拥塞控制机制。

3. 传输方式(Byte Stream vs Datagram)

  • TCP:面向字节流(Byte Stream)。在 TCP 视角下,应用层写入的数据只是一串无结构、连续的字节流。TCP 会根据 MSS 和滑动窗口大小随意切分或合并数据。这意味着应用层多次发送的小数据包可能被合并成一段传输(Nagle 算法),一次发送的大数据包也可能被拆成多个 TCP 段发送,这正是“粘包/拆包”的本质来源。
  • UDP:面向数据报(Datagram)。保留应用层消息边界。应用层调用一次 sendto 发送多大的报文,内核就打包成一个 UDP 报文发出(若超过 MTU 则在 IP 层分片);接收端一次 recvfrom 必须读取完整的一个报文,不会出现报文粘连。

4. 关键维度对比表

对比维度
TCP
UDP
连接状态
面向连接(三次握手/四次挥手)
无连接
可靠性
强可靠(ACK、重传、排序、去重)
尽力而为(可能丢包、乱序、重复)
首部开销
20 ~ 60 字节(包含选项字段)
固定 8 字节
传输形式
面向连续字节流(无边界)
面向独立数据报(保留边界)
控制机制
流量控制(滑动窗口)+ 拥塞控制
无(需应用层自行实现)
传输效率
较慢(握手开销、ACK延迟、重传等待)
极高(零额外协议负担)
典型场景
RPC 调用、文件传输、Web 浏览(HTTP/1.1、H2)
实时音视频(WebRTC)、DNS 查询、广播/组播

二、微服务实践:为什么 RPC 极度依赖 TCP?

在以 Apache dubbo-go 为代表的微服务 RPC 场景中,服务间的调用本质上是进程间远程方法调用(Remote Procedure Call)。

1. 业务本质决定传输选型

微服务架构承载的是核心业务逻辑(如订单创建、用户鉴权、支付扣款、状态机流转):
  • 数据正确性零容忍:任何请求参数或响应字段的丢失、错位,都可能引发严重的资损与业务状态不一致。
  • 协议透明度要求:如果选型原生 UDP,应用层/框架层必须自行实现一套完整的滑动窗口、乱序重组、丢包重传和超时确认逻辑,这无异于在应用层重新发明一套 TCP。
因此,借助操作系统的 TCP 协议栈实现可靠传输,是经典微服务 RPC 框架的标准解法。

2. 字节流挑战:TCP 粘包/拆包在 dubbo-go 中的解法

虽然 TCP 提供了可靠传输,但其无边界的字节流特性给 RPC 协议解析带来了挑战:发送端连续发送的两个 RPC 请求包,在接收端可能被合并在同一次网络读取中(粘包);或者一个较大的 RPC 请求被拆分到了多次网络读取中(拆包)。
在 dubbo-go 的网络传输层与编解码层,解决粘包/拆包的核心思想是:设计自包含长度的定长协议头(Header-Payload Framing)。

Dubbo 协议帧结构解析

  1. Magic Number(魔数,16-bit):固定为 0xdabb,用于快速校验当前字节流是否为合法的 Dubbo 报文起始位置,过滤非法探测与异常流。
  1. Header 固定长度(16 字节):前 16 字节包含了序列化协议 ID、请求/响应标记、双向调用标记、状态码、全局唯一的 Request ID 以及 Data Length。
  1. Data Length(32-bit 整型):明确标注了后续变长 Payload 的实际字节数。

dubbo-go 源码级的解码状态机逻辑

在 dubbo-go 的 Codec(编解码器)实现中,典型的解码流程遵循严格的状态机控制:
通过这种固定 Header + Length 字段的设计,配合底层的环形缓冲区(Ring Buffer)或带游标的字节切片,dubbo-go 完美化解了 TCP 字节流带来的粘包与拆包难题。

三、反思与权衡:为什么音视频会议宁愿丢帧也要用 UDP?

与微服务 RPC 对“绝对可靠”的执念相反,实时音视频会议(如 Zoom、腾讯会议、WebRTC 通话)选择站在了 UDP 一侧。

1. 实时性的硬约束(Latency Bound)

  • 心理学与声学研究表明,双向语音通话的端到端单向时延必须控制在 200ms 以内,超过 400ms 会产生明显的对话打架与卡顿感。
  • TCP 的“队头阻塞”(Head-of-Line Blocking)是实时音视频的致命克星:
  • 如果第 3 号数据包在网络中丢失,即使 4、5、6 号包已经到达接收端内核,TCP 协议栈为了保证“按序交付”,也会强行扣留 4、5、6 号包,禁止上层应用读取。
  • 必须等待发送端经历超时或三次重复 ACK 重传 3 号包并确认后,所有数据才能一并交给应用。
  • 这一等待过程往往耗时数百毫秒甚至数秒,会导致画面瞬间严重冻结。

2. “宁可丢帧/降质,不可卡顿”

在音视频场景下:
  • 数据的时效性极强:200ms 之前的音频采样或视频帧,对当前播放来说已经失去意义;补发一个过期的旧帧不仅毫无帮助,还会挤占当前宝贵的带宽。
  • 人眼的视觉容错与算法补偿:
  • 视频编解码器具有容错能力,偶尔丢失几个 P 帧或宏块,可以通过前后帧插值(Frame Interpolation)或局部马赛克平滑过渡。
  • 配合 FEC(前向纠错,冗余校验)、Jitter Buffer(抗抖动缓冲区) 和 ARQ 动态受控重传(如 WebRTC 只针对关键 I 帧做极短周期的重传),在应用层实现细粒度的丢包控制。

四、技术视野延伸:QUIC / HTTP/3 与下一代 RPC 的演进

架构选型从来不是非黑即白的二选一,而是伴随技术演进而不断融合。

1. QUIC 的破局点

TCP 的可靠性机制固化在操作系统内核中,升级周期漫长,且 Stream 之间的队头阻塞无法在 TCP 层面解耦。QUIC(Quick UDP Internet Connections) 选择以 UDP 为基础载体,在用户空间(User Space)重新实现了一套现代化的可靠传输机制:
  1. 单流独立的可靠传输,彻底消除流级别的队头阻塞:单个 Stream 发生丢包,仅阻塞该 Stream,其他并发 Stream 照常传输。
  1. 极速建连(0-RTT / 1-RTT):将传输握手与 TLS 1.3 安全握手合并,大幅减少网络往返耗时。
  1. 连接迁移(Connection Migration):使用 64 位的 Connection ID 代替传统的 IP+Port 四元组标识连接,即使在 Wi-Fi 和蜂窝网络切换时也能保持连接不中断。

2. 对微服务 RPC 架构的启示

在云原生与跨机房/跨数据中心(WAN)通信场景下,基于 QUIC 的 RPC(如 gRPC over HTTP/3、Dubbo 3.x 对 Triple 协议与 QUIC 的探索)正逐步成为前沿方向。它兼具了 TCP 的可靠数据保障与 UDP 的低延迟、抗网络抖动特性。

五、总结

  1. 总述核心区别:从连接性(有/无状态)、可靠性(强保障/尽力而为)、传输模式(字节流/数据报)三点切入,建立系统框架。
  1. 结合微服务 RPC 深度剖析(以 dubbo-go 为例):说明 RPC 对数据正确性的零容忍决定了必须依赖 TCP;进一步引申 TCP 字节流带来的粘包/拆包问题,并从源码架构层面阐述 Magic Number + Header Length + Payload 的定长帧解码策略。
  1. 对比音视频通话的权衡(Trade-off):指出 TCP 队头阻塞是实时交互的硬伤,说明音视频场景“时效优先、轻度容错”的特征,解释 UDP 配合 FEC/Jitter Buffer 是更优解。
  1. 展示前瞻视野(QUIC/HTTP/3):总结 UDP 的灵活性使得传输层控制逻辑能够上移至用户态,引出 QUIC 对多路复用队头阻塞的解决与下一代 RPC 的演进方向。
回到首页