【融云分析】去中心化的 RTC 通信服务平台
编者按:去中心化的RTC网络无需关心其它媒体服务状态,可快速增加地域媒体服务节点部署,与信令服务无耦合。本文来自融云联合创始人,CTO杨攀在LiveVideoStackCon 2019上海的演讲内容,由LiveVideoStack整理而成。
大家好,我叫杨攀,从开始工作至今有17年了,一直在从事电信、通信、社交以及开放平台领域相关的工作。大约在2004年左右,MSN刚开始进入中国并落地,当时我们的团队在上海将一些MSN的美国业务在本地做了电信运营商的落地。后续,我也参与到了整个飞信团队的建设之中,目前融云的研发团队就是之前中国移动飞信的核心研发团队,整个团队从研发到产品再到运营在一起工作了大约12年之久。
一、背景介绍
融云做的是通信云服务,可以说是基于IP的虚拟通信运营商,我们希望未来所有在Internet上的IP流量,包括消息、语音片段、视频片段、红包、表情、音频通话和视频通话等等,所有的这些通信都能承载在我们自己建设的全球通信网上,而这同样也是我们的使命。因此,目前我们在全球大规模地铺设了自己的网络,包括在北京、新加坡和北美建设的三个大数据中心,在全球有数百个接入节点和数千个加速节点。
本次要与大家分享的主要内容就是在架构尺度上的部分技术经验与积累。
二、分布式无级联的RTC架构
首先,为大家介绍分布式无级联的RTC架构。对于RTC的架构,在WebRTC中的定义是一个Peer到Peer的通信。其中并没有直接给出一个明确的标准来告诉你如何去做信令服务、媒体服务等。那么,一个最简单的分布式媒体服务是什么样的呢?
一般的基本模式是,A用户和B用户首先通过一个信令服务,信令服务为A和B分别分配媒体服务,然后帮助它们之间建立一个联系。对于这种简单分布式但并不支持级联的RTC架构,它的优点是每一个媒体服务本身都不需要和其它的媒体服务建立连接,并且不会进行网络优化。但是,它最大的问题就是当我们给A客户端分配一个媒体服务后,B客户端也是需要连接同一媒体服务的。假如我们先给A客户端就近分配一个媒体服务,此时A客户端和媒体服务之间连接的质量是非常好的,但是如果A客户端和B客户端不在同一地区,B客户端也许距离这个媒体服务非常远,中间的网络就可能会非常不稳定,此时A客户端和B客户端通过这个媒体服务建立的通信就是存在问题的。因此,这种模式只适用小规模范围的通信,如城域或者是公司内部的私网。
下面,将介绍有级联的RTC架构是如何实现的。
三、分布式有级联的RTC架构
有级联的RTC架构则要求A客户端和B客户端分别找到不同的媒体服务来进行通信,媒体服务之间也要做级联的通信,这样就能解决上述无级联RTC架构存在的问题。如上图所示,我们可以先为左边的Client找到一个对它来讲质量最好的媒体服务,然后再为右边的Client找到一个质量最好的媒体服务,两个媒体服务之间还要再通过一些网络优化的手段来保证它们的通信质量。上图系统中的蓝色部分叫做Signal Server,Client可以通过Signal Server和Media Server进行SDP交换。
分布式有级联的RTC架构可以实现链路的优化,但同时我们也不难发现,Signal Server和Media Server之间存在的耦合问题。这是因为所有的Media Server都需要在Signal Server中进行注册登记以进行管理,并且Signal Server还要和Media Server之间保持一个健康状态的检查,比如做一个TCP的长连接、做一个心跳包。此外,Signal Server不仅需要知道Media Server里有哪些用户正在使用流媒体通信,还需要知道它的用户状态。一方面,对于紧的耦合,当部署一个新的媒体服务时,就会需要很复杂的工程实施,因为在很多地方均要Update配置。另一方面,如果在通话过程中发现媒体服务或者信令服务之间存在一些异常状态,则会导致整个通话断掉,因为他们两个之间的耦合非常紧密。到目前为止,大家能够在市面上看到的开源解决方案基本上都是按这个模式去设计的。在电信运营商领域,Signal Server最典型的就是用SIP协议来实现的,包括我们之前做飞信也是用的一个SIP的简化协议SIPC。还有一种方案就是,可以搭一个XMPP的服务器,用它来实现Presence管理,所谓的Presence管理与SIP一样,就是用一条IM通道来做Signal Server。
在这一部分,我们分析了分布式有级联RTC架构的优点和缺点。接下来,我们一起来看看融云对分布式RTC网络的思考。
四、融云对分布式RTC网络的思考
如上所述,由于信令服务器和媒体服务是有耦合的,我们上线或下线任何一个媒体服务器均要在Signal Server里Update相关状态和配置。因此,我们的第一个诉求就是要设计一种将信令服务和媒体服务解耦开来的架构;第二个诉求就是要使得我们的信令服务和媒体服务之间能不管对方的状态如何,让它们不需要状态同步;第三个诉求就是让每一个媒体中心都是独立的;第四个诉求就是要降低新建与维护媒体中心的成本,因为通信云服务有数以千计或万计的机器和节点要管理;最后一个诉求就是要全面复用融云即时通讯通道。
上图是融云的分布式RTC网络架构,我们将Signal Server换成了融云的IM基础设施。简单来说,IM是用来发消息的,它实际上就是把一段数据通过一个长连接的、永远在线的通道从一端推送到另外一端,而且该服务要保证这条通道永远是可用的,同时发的每一个信令、指令都不能丢失,并且要以最快的速度到达。总的来说,这就是Signal Server的使命。
接下来,我将为大家详细讲解融云的RTC建连过程。
如上图所示包含有五个角色,分别是Client A、Client A对应的Media Server、IM Server、Client B对应的Media Server、Client B。Client A是通信的发起方,IM Server就是我们的Signal Server。在这个架构里面,我们引入Pub/Sub模型来实现解耦,下面将分两部分讲解。
Pub过程:Client A会利用Smart DNS直接找到自己对应的Media Server,然后调用该Media Server上开放的一个HTTP接口,调用该接口是为了传递传Token、Room ID/Channel ID,以及交换SDP,这个在后面会详细解释。调用完之后,Media Server会返回该Media Server的IP地址和Client A在Media Server上注册后所分配的Resource ID,Resource ID是Client A在Media Server上唯一的身份标识。Client A接收到Media Server返回的信息后就可以直接与Media Server建立RTC连接,接着就可以开始利用信令通道了。之后IM Server要将Client A呼叫Client B的指令Push给Client B,并且会将Media Server返回给Client A的信息直接Send给Client B。此时,Pub过程就完成了。
Sub过程:与前面相同,Client B也要通过Smart DNS找到一个相对来说质量最好的Media Server,然后调用其另外一个接口将刚才传过来的信息告诉这个Media Server。当Client B对应的Media Server拿到了Client A对应的Media Server的信息后,由Resource ID就可以知道要将Client A和Client B之间建立连接,在内部建立关联后返回一个ACK,说明已经调用成功。一旦Client A和Client B建立RTC连接成功后,Client A对应的Media Server和Client B对应的Media Server就建立起了级联。
当RTC的通道连接建立成功后,去中心化完成,此时我们就完成了Media Server和Signal Server之间的解耦。
总结一下,融云的RTC建连过程采用了极简的接口设计。如上述的时序图,有几次HTTP调用实际上全都是通过一个HTTP接口来实现的,而这一个HTTP接口通过传递不同的参数就非常简单的实现了发布/取消发布流,SFU和MCU的订阅/取消订阅。
下面将详细讲解一下在前面提到的Media Server。
对于Media Server,我们可以将其理解为在一台物理硬件的服务器上面部署了一套服务。但事实上,对于大规模的云厂商来讲,一般是在某一个地方建立一个数据中心,在里面会投入很多的机器来运转。一个媒体服务中心的架构设计往往非常简单,对于左边的HTTP请求要做Load Balance,然后把它分布在其他各种平台的Media Server上,并且在中间还加了一个反向代理。在数据中心里虽然有很多的媒体服务,但如果我们不做任何策略的话,就可能会出现以下情况:当三个人在一个房间聊天时,可能会被分配到了两台Media Server上,即在数据中心内还需要Media Server之间的通信,这样是十分影响性能和质量的。那么,我们该如何解决这个问题呢?如前所述,调用接口时要传Token、Room ID/Channel ID、SDP。因此,我们可以通过算法将Room ID相同的用户归并到同一台Media Server上,只要这个房间内的订阅人数没有超过该Media Server的物理上限,则可以保证该房间里用户全在一个Media Server上进行通信,此时的性能是非常好的。除了上述情况外,还有另外一个问题,例如当前进行会议的房间的人数特别多,而且用户数超过了Media Server所能承载的业务量。对于这种情况,我们就需要进行打散,也就是将用户分散在不同的Media Server上。
接下来,总结一下我们在媒体服务方面除了上述内容之外还做了哪些事情。在进行HTTP接口调用时,HTTP接口支持QUIC,可减少交互握手的次数来优化性能。另外,我们还做了媒体服务的端口收敛以及尽可能的去实现单中心间媒体服务的0调用。
接下来,针对前面提出的问题来总结一下结果:1)我们按照新设计的架构模型实现了信令服务和媒体服务的解耦,当上线一个新的媒体服务时,无需在信令服务里添加任何注册配置,唯一要做的就是在Smart DNS里为这个媒体服务增加一条记录;2)信令和媒体服务之间不存在任何调用关系,所以也就不存在任何数据和状态的同步;3)媒体中心间也不需要状态同步;4)我门已经把媒体服务管理和添加的成本降到非常低的水平;5)直接复用融云的通讯通道,在融云RTC的SDK里面已经内涵了一个精简版的IM协议栈。
下面将介绍一下融云的RTC全球网络。
五、融云RTC全球网络
融云是一家覆盖全球的云通信服务商,目前已经建立了全球的通信网络,遍布中国、东南亚、中东等地。只要客户需要,我们的工程团队就可以去当地建设数据中心,将整个的通信网络基础设施铺到那里。目前,我们已经将全新建设一个Media Server的成本降到非常低的程度,以至于只仅添加一条DNS记录就可以搞定,这也是我们整个后端的研发团队引以自豪的地方。
那么,我们在全球网络上做了哪些工作呢?首先,我们引入了一个新的概念HTTPDNS,融云每天有几千万的活跃用户,因此连接访问的次数可能会是特别大数量级的。根据我们手里掌握数据的分析结果来看,DNS是影响连通率指标的罪魁祸首,尤其在国内复杂的网络环境下。因此,需要引入HTTPDNS来进一步提高通信质量。其次,媒体中心间的物理链路优化。级联的一种简单方式就是物理连接,现在几乎所有的厂商都会花钱进行物理链路的优化。此外,对于跨厂商或者在网络比较复杂地区可能要建设一些物理服务器,那我们就要解决逻辑链路的优化,在这里面通常是采用一些转发的策略,其中的基础逻辑就是收集数据、实时分析数据然后做出决策去实现调度。
接下来,再补充介绍一些其它的技术点。
1)RTC鉴权
在最初的实时通信模型架构中,根据Room ID/Channel ID直接加入即可订阅它的流,并且可以看到它里面的内容,这就导致了存在安全的隐患。那么如何解决这个问题呢?解决方法就是在前面所讲到的模型中调HTTP接口时要传一个Token。具体来讲,当两个客户端建立连接时,在同步调用Signal Server的过程中会传一个Token回来,Token是信令服务调用后台的密钥服务所分发的一个令牌。当拿着这个令牌去连Client对应的Media Server时,Media Server会Check令牌隐含的信息是否与要建立连接Client的Room ID/Channel ID相匹配。如果不匹配,则没有权限查看里面的内容。验证是否匹配的基本逻辑是上图中的Key Server和Media Server共享一套密钥算法和密钥,它们都是部署在数据中心里的,里面的协议也都是我们内部来实现的。此外,在这里还有一个算法来验证Token是否有二次的I/O请求和调用,这是一个常见的大规模高并发系统架构设计的基础原理,即尽量在某些场合巧妙的通过一些算法和验证减少I/O的请求和调用。
2)融云IM加速网络
接下来,为大家介绍一下融云IM的加速网络。从上图中可以看出,我们的加速网络模型是一个混合云,包含国内私有部署、国外私有部署,目前已经实现了国内外的互通。需要跟大家介绍的是,国内和国外的网络之间访问的质量是受到影响的,因此对于国内外的互通还需要进行一些专门的优化。这些优化说白了就是砸钱来解决问题,因此我们在国内有自己的加速节点,在国外也有自己的加速节点,并且还可以在国内外实现私有部署,包括把信令服务私有部署在用户那里。举例说明,目前我们有一个客户是一家国内顶尖的IT企业,它的员工大概有十几万人,遍布在全球的各个城市和大区,他们希望通过我们帮助建立企业内部十几万人之间的IM与RTC沟通。由于全球各个地区网络情况复杂,他们自己的团队无法保证网络质量的问题,对于链路情况复杂和距离较远的情况也无法解决。最终,他们采用的是融云的解决方案,通过在北京的数据中心私有部署了一套IM的基础设施服务,然后租用了融云的全球加速网络,采用的就是经典的混合云模式。
3)融云RTC SDK
融云RTC SDK就是我们将所有东西解耦之后所得到的另一个副产品。实际上,音视频通信云服务领域已经发展多年,在这个领域有一个很有意思的现象就是很多厂商把能力和功能耦合在一起。这就会导致如果我想做一个场景,那么就需要添加大量新的接口,而在大量新加的代码里隐含着一个业务的场景和逻辑。前面讲过,我们将RTC建连过程转变成了Pub/Sub模型,使得系统变得极其简单,如同几块乐高积木一样。因此,无论我们想要引入何种逻辑,比如两人通话、多人会议、千人的会议、小班课、直播连麦等等。这些场景都可以通过简单的几个模块直接搭建出来,而我们要做的就是在上层将这一段业务场景或逻辑封装成一个SDK,目前已有的SDK包括Call Kit、Call Lib等等,其中Kit指的就是UI Competent。举例说明,微信音视频电话的场景,我们的SDK包含了这个场景的UI组件和通信组件,用户想要实现这个场景直接引用SDK即可,不用再做任何二次开发的工作。类似地,会议会控、直播的UI组件和通信组件等等都会封装成SDK。并且,我们会随着用户的需求通过这些积木实现不同的业务场景。
接下来总结一下融云RTC SDK的特点:1)我们真正做到了SDK组件自底向上地单向依赖,并且SDK组件没有任何交叉调用;2)架构中间的可替换的信令层Signal Server与Media Server没有任何关系,这意味着用户可以使用我们的Media Server,使用自己的Signal Server,这个架构完全实现了解耦;3)所有场景都全部实现组件化,因为它们的底层就是用积木搭建出来。
六、未来计划
最后,我们的架构设计未来计划是可以将Media Server做成Dockerfile,放到网站上供大家下载。我们还可以支持混合云模式,实现RTC Media Server的众包。众包指的就是用户可以找寻合适的网络,通过自己的硬件部署一个Dockerfile、架设一个自己写的Media Server,还可以成为融云全球加速通信网的节点中的一员。第二种模式就是用户租用融云的全球通信网,但可以实现私有的信令部署。再有一种模式就是用户可以按照模型自建媒体服务,然后自建私有的信令部署。