酷蚁综合网
当前位置:首页»情感文章»

怎么让不可靠的UDP可靠?

最近和很多实时音视频领域的朋友交流中都有谈论到 RUDP(Reliable UDP),这其实是个老生常谈的问题,RUDP 在很多著名的项目上都有使用,例如 Google 的 QUIC 和 webRTC。在 UDP 之上做一层可靠,很多朋友认……

专题: 最不可靠的就是感情 英语网上聊天 

最近和很多实时音视频领域的朋友交流中都有谈论到 RUDP(Reliable UDP),这其实是个老生常谈的问题,RUDP 在很多著名的项目上都有使用,例如 Google 的 QUIC 和 webRTC。在 UDP 之上做一层可靠,很多朋友认为这是很不靠谱的事情,也有朋友认为这是一个大杀器,可以解决实时领域里大部分问题。

作为教育公司,学霸君在很多实时场景下确实使用 RUDP 技术来解决我们的问题,不同场景我们采用的 RUDP 方式也不一样。先来看看学霸君哪些场景使用了 RUDP:

全局 250 毫秒延迟的实时 1V1 答疑,采用的是 RUDP + 多点 relay 智能路由方案。500 毫秒 1080P 视频连麦互动系统,采用的是 RUDP + PROXY 调度传输方案。6 方实时同步书写系统,采用的是 RUDP+redo log 的可靠传输技术。弱网 Wi-Fi 下 Pad 的 720P 同屏传输系统,采用的是 RUDP +GCC 实时流控技术。大型直播的 P2P 分发系统,通过 RUDP + 多点并联 relay 技术节省了 75% 以上的分发带宽。

涉及到实时传输我们都会先考虑 RUDP,RUDP 应用在学霸君核心传输体系的各个方面,但不同的系统场景我们设计了不同的 RUDP 方式,所以基于那些激烈的讨论和我们使用的经验我扒一扒 RUDP。

其实在实时通信领域存在一个三角平衡关系:成本、质量和时延三者的制约关系:

图 1

也就是说投入的成本、获得的质量和通信的时延之间是一个三角制约 (LEQ) 关系,所以实时通信系统的设计者会在这三个制约条件下找到一个平衡点,TCP 属于通过增大延迟和传输成本来保证质量的通信方式,UDP 是通过牺牲质量来保证时延和成本的通信方式,所以在一些特定场景下 RUDP 更容易找到这样的平衡点。RUDP 是怎么去找这个平衡点的,就要先从 RUDP 的可靠概念和使用场景来分析。

在实时通信过程中,不同的需求场景对可靠的需求是不一样的,我们在这里总体归纳为三类定义:

尽力可靠:通信的接收方要求发送方的数据尽量完整到达,但业务本身的数据是可以允许缺失的。例如:音视频数据、幂等性状态数据。无序可靠:通信的接收方要求发送方的数据必须完整到达,但可以不管到达先后顺序。例如:文件传输、白板书写、图形实时绘制数据、日志型追加数据等。有序可靠:通信接收方要求发送方的数据必须按顺序完整到达。

RUDP 是根据这三类需求和图 1 的三角制约关系来确定自己的通信模型和机制的,也就是找通信的平衡点。

说到这里可能很多人会说:干嘛那么麻烦,直接用 TCP 好了! 确实很多人也都是这样做的,TCP 是个基于公平性的可靠通信协议,但是在一些苛刻的网络条件下 TCP 要么不能提供正常的通信质量保证,要么成本过高。为什么要在 UDP 之上做可靠保证,究其原因就是在保证通信的时延和质量的条件下尽量降低成本,RUDP 主要解决以下相关问题:

端对端连通性问题:一般终端直接和终端通信都会涉及到 NAT 穿越,TCP 在 NAT 穿越实现非常困难,相对来说 UDP 穿越 NAT 却简单很多,如果是端到端的可靠通信一般用 RUDP 方式来解决,场景有:端到端的文件传输、音视频传输、交互指令传输等等。弱网环境传输问题:在一些 Wi-Fi 或者 3G/4G 移动网下,需要做低延迟可靠通信,如果用 TCP 通信延迟可能会非常大,这会影响用户体验。例如:实时的操作类网游通信、语音对话、多方白板书写等,这些场景可以采用特殊的 RUDP 方式来解决这类问题。带宽竞争问题:有时候客户端数据上传需要突破本身 TCP 公平性的限制来达到高速低延时和稳定,也就是说要用特殊的流控算法来压榨客户端上传带宽,例如:直播音视频推流,这类场景用 RUDP 来实现不仅能压榨带宽,也能更好地增加通信的稳定性,避免类似 TCP 的频繁断开重连。传输路径优化问题:在一些对延时要求很高的场景下,会用应用层 relay 的方式来做传输路由优化,也就是动态智能选路,这时双方采用 RUDP 方式来传输,中间的延迟进行 relay 选路优化延时。还有一类基于传输吞吐量的场景,例如:服务与服务之间数据分发、数据备份等,这类场景一般会采用多点并联 relay 来提高传输的速度,也是要建立在 RUDP 上的(这两点在后面着重来描述)。资源优化问题:某些场景为了避免 TCP 的三次握手和四次挥手的过程,会采用 RUDP 来优化资源的占用率和响应时间,提高系统的并发能力,例如 QUIC。

不管哪类场景,都是要保证可靠性,也就是质量,那么在 UDP 之上怎么实现可靠呢?答案就是重传

IP 协议在设计的时候就不是为了数据可靠到达而设计的,所以 UDP 要保证可靠,就依赖于重传,这也就是我们通常意义上的 RUDP 行为,在描述 RUDP 重传之前先来了解下 RUDP 基本框架,如图:

图 2

RUDP 分为发送端和接收端,每一种 RUDP 在设计的时候会做不一样的选择和精简,概括起来就是图中的单元。RUDP 的重传是发送端通过接收端 ACK 的丢包信息反馈来进行数据重传,发送端会根据场景来设计自己的重传方式,重传方式分为三类:定时重传、请求重传和 FEC 选择重传。

定时重传

定时重传很好理解,就是发送端如果在发出数据包(T1)时刻一个 RTO 之后还未收到这个数据包的 ACK 消息,那么发送端就重传这个数据包。这种方式依赖于接收端的 ACK 和 RTO,容易产生误判,主要有两种情况:

对方收到了数据包,但是 ACK 发送途中丢失。ACK 在途中,但是发送端的时间已经超过了一个 RTO。

所以超时重传的方式主要集中在 RTO 的计算上,如果你的场景是一个对延迟敏感但对流量成本要求不高的场景,就可以将 RTO 的计算设计得比较小,这样能尽最大可能保证你的延时足够小。

例如:实时操作类网游、教育领域的书写同步,是典型的用 expense 换 latency 和 quality 的场景,适合用于小带宽低延迟传输。如果是大带宽实时传输,定时重传对带宽的消耗是很大的,极端情况会有 20% 的重传率,所以在大带宽模式下一般会采用请求重传模式。

请求重传

请求重传就是接收端在发送 ACK 的时候携带自己丢失报文的信息反馈,发送端接收到 ACK 信息时根据丢包反馈进行报文重传。如下图:

图 3

这个反馈过程最关键的步骤就是回送 ACK 的时候应该携带哪些丢失报文的信息,因为 UDP 在网络传输过程中会乱序会抖动,接收端在通信的过程中要评估网络的 jitter time,也就是 rtt_var(RTT 方差值),当发现丢包的时候记录一个时刻 t1,当 t1 + rtt_var < curr_t(当前时刻),我们就认为它丢失了。

这个时候后续的 ACK 就需要携带这个丢包信息并更新丢包时刻 t2,后续持续扫描丢包队列,如果 t2 + RTO cwnd, 继续保证 DRAIN 状态,如果 flight_size=2% &&loss =10%,会认为传输过载,进行调小传输带宽。

GCC 的接收端是根据数据到达的延迟方差和大小进行 KalmanFilter 进行带宽逼近收敛,具体的细节不介绍了,请查看 http://www.jianshu.com/p/bb34995c549a。

这里值得一说的是 GCC 引入接收端对带宽进行 KalmanFilter 评估是一个非常新颖的拥塞控制思路,如果实现一个尽力可靠的 RUDP 传输系统不失为是一个很好的参考。

但这种算法也有个缺陷,就是在网络间歇性丢包情况下,GCC 可能收敛的速度比较慢,在一定程度上有可能会造成 REMB 很难反馈给发送端,容易出现发送端流控失效。GCC 在三角平衡关系算一个以 quality 和 expense 换取 latency 的案例。

其实在很多场景是不用拥塞控制或者只要很弱的拥塞控制即可,例如:师生双方书写同步、实时游戏,因为本身的传输的数据量不大,只要保证足够小的延时和可靠性就行,一般会采用固定窗口大小来进行流控,我们在系统中一般采用一个 cwnd =32 这样的窗口来做流控,ACK 确认也是通过整个接收窗口数据状态反馈给发送方,简单直接,也很容易适应弱网环境。

RUDP 除了优化连接、压榨带宽、适应弱网环境等以外,它也继承了 UDP 天然的动态性,可以在中间应用层链路上做传输优化,一般分为多点串联优化和多点并联优化。我们具体来说一说。

在实时通信中一些业务场景对延迟非常敏感,例如:实时语音、同步书写、实时互动、直播连麦等,如果单纯的服务中转或者 P2P 通信,很难满足其需求,尤其是在物理距离很大的情况下。

在解决这个问题上 SKYPE 率先提出全球 RTN(实时多点传输网络),其实就是在通信双方之间通过几个 relay 节点来动态智能选路,这种传输方式很适合 RUDP,我们只要在通信双方构建一个 RUDP 通道,中间链路只是一个无状态的 relay cache 集合,relay 与 relay 之间进行路由探测和选路,以此来做到链路的高可用和实时性。如下图:

图 9

通过多点 relay 来保证 RUDP 进行传输优化,这类场景在三角平衡关系里是典型的用 expense 来换取 latency 的案例。

在服务与服务进行媒体数据传输或者分发过程中,需要保证传输路径高可用和带宽并发,这类使用场景也会使用传输双方构建一个 RUDP 通道,中间通过多 relay 节点的并联来解决,如下图所示:

图 10

这种模型需要在发送端设计一个多点路由表探测机制,以此来判断各个路径同时发送数据的比例和可用性,这个模型除了链路备份和增大传输并发带宽外,还有个辅助的功能,如果是流媒体分发系统,我们一般会用 BGP 来做中转,如果节点与节点之间可以直连,这样还可以减少对 BGP 带宽的占用,以此来减少成本。

到这里 RUDP 的介绍也就结束了,说了些细节和场景相关的事,也算是个入门级的科普文章。RUDP 的概念从提出到现在也差不多有 20 年了,很多从业人员希望通过一套完善的方案来设计一个通用的 RUDP,我个人觉得这不太可能,就算设计出来了,估计和现在 TCP 差不多,这样做的意义不大。

RUDP 的价值在于根据不同的传输场景进行不同的技术选型,可能选择宽松的拥塞方式、也可能选择特定的重传模式,但不管怎么选,都是基于 expense(成本)、latency(时延)、quality(质量)三者之间来权衡,通过结合场景和权衡三角平衡关系 RUDP 或许能帮助开发者找到一个比较好的方案。

袁荣喜,学霸君资深架构师,16 年的 C 程序员,擅长 P2P 通信网络、TCP/IP 通信协议栈和鉴权加密技术,2015 年加入学霸君,负责构建学霸君的智能路由实时音视频传输系统和网络,解决音视频通信的实时性的问题。

感谢雨多田光对本文的审校。

评价本文

专业度风格编辑观点主编观点提交提交Author Contacted关注 Topic相关主题:语言 & 开发语言 & 开发关注229 他的粉丝架构 & 设计架构 & 设计关注599 他的粉丝RTCRTC关注0 他的粉丝计算机网络计算机网络关注0 他的粉丝

相关内容

相关厂商内容

从C#看开放对编程语言发展的影响 Netflix的工程文化:是什么在激励着我们? 百度贴吧之父:产品经理的发现和成长 Apache Kafka的过去,现在,和未来

相关赞助商

您需要 注册一个InfoQ账号 或者 登录 才能进行评论。在您完成注册后还需要进行一些设置。告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我社区评论 重新发明选择重传?重新实现BBR? by 范 扬 Posted

重新发明选择重传?重新实现BBR? by 范 扬

炒冷饭? 喜欢回复回到顶部关闭 by 发布于 查看回复回到顶部关闭主题 您的回复 引用原消息

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我关闭主题您的回复

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

本文关键字:

您至少需要输入5个字

相关内容

编辑精选

copyright © 2017 http://www.coolbz.cn 酷蚁综合网 版权所有