构建基于浏览器的Web P2P网络直播

简介: 在2021年的互联网时代,越来越多的网络直播节目相继涌现。浏览器是用户最易接触的渠道之一,聚集了大量观看直播的用户。当用户们同时观看直播内容时,服务器承受的负载随着用户量的增加而增大,会导致播放的卡顿,延迟等用户体验的下降;而且高昂的服务器带宽成本也不容忽视。那么是否存在一套解决方案,在保证用户体验与服务质量的前提下,又可以有效的降低服务器的负载与带宽呢?那就是接下来要介绍的Web P2P技术了。

一、Web P2P的前世今生

2010年,Adobe在Flash Player 10.0推出了实时流媒体RTMFP,使用RTMFP在Flash Player之间进行P2P成为可能。在随后的几年内,该协议在网络上如雨后春笋般的被广泛部署,但是从2020年末开始,各家的浏览器都已经彻底不支持Flash了。我们又应该如何在Web里面使用P2P呢?

诞生于2011年的WebRTC技术,在Google、Microsoft、Apple、Mozilla等大厂的支持下,成为了H5的标准,并且Chrome、Edge、Safari、Firefox等主流浏览器也都支持WebRTC。所以就可以通过WebRTC来实现P2P了。

下文把基于WebRTC实现的HTML5 P2P简称为H5 P2P。

二、WebRTC简介

WebRTC的总体架构如下图所示,如果是浏览器开发者,通常需要关注并实现WebRTC C++ API,而我们的目标是基于浏览器实现P2P,所以只需要关注Web API即可。

image.png

整体的H5 P2P都是基于RTCPeerConnection和RTCDataChannel来实现的,只是实现数据层面的P2P,不包含音视频通信的内容。

三、总体架构

image.png

1. H5 P2P客户端

主要包含通信模块、传输模块、节点管理、调度模块、存储模块和统计模块:

通信模块主要负责和服务端(上图中的Index、CPS、Tracker)进行信令的通信

传输模块:包含HTTPClient和基于RTCDataChannel实现的RTCClient(上传&下载)

节点管理:不同用户间P2P主被动连接、断开、淘汰、资源信息同步

调度模块:根据buffer水位、分片信息、节点质量和规模进行CDN/P2P调度

存储模块:负责媒体数据的存储、排序、以及淘汰

统计模块:包含系统运行的埋点的实现

2. H5 P2P服务端

主要包含Index、CPS、Tracker和Stun服务:

Index:索引服务,提供其他服务地址。

CPS:资源属性服务,将直播流的URL转换为RID。

Tracker:资源追踪服务,主要存储用户和资源之间的索引关系。

MQTT:信令服务,转发用户间建立P2P连接的offer/answer/candidate SDP协议。

Stun:采用coturn部署,主要用户节点之间建立对等连接的UDP穿透。

四、阶段流程

下图简略的展示了整体方案的各个阶段、流程:

image.png

Step 1:网页打开,首先向Index服务请求其他服务的地址,保存于内存中

Step 2:客户端收到直播请求,向CPS发送请求将URL转换为资源ID(RID),相同内容相同清晰度的直播流的资源ID(RID)是相同的,表明可以互相分享数据

Step 3:客户端首先会启动HTTPClient进行数据下载,优先保证秒播。同时做以下2件事

a. 客户端向Tracker服务发送Address协议,获取其他正在观看该直播的用户地址,待后续建立连接,分享数据

b. 客户端向Tracker服务发送Publish协议,将自己的信息告知Tracker,使得别人可以即使搜索到自己,进行数据分享

Step 4:向从Tracker获取的其他用户建立连接,彼此交换信息,数据分享

五、连接建立

假设在Peer1和Peer2之间传输数据,那么在传输之前,首先需要建立连接。在WebRTC中,浏览器间通过ICE框架建立对等连接,主要包含Stun、TURN,下面分别简单介绍一下:

1. ICE

ICE(Interactive Connectivity Establishment)提供的是一种P2P连接框架,统一各种NAT穿透技术(STUN,TURN)。基于offer/answer/candidate模式,通过多次地址交换,然后进行连通性测试,穿透用户网络间各类防火墙。ICE主要包含STUN、TURN等协议。

2. STUN

STUN(Simple Traversal of UDP Through NAT)允许位于NAT设备后的客户端找到自己的公网IP/Port地址,以及查询出自己的NAT设备类型,通过这些信息使得两个同时位于NAT后的2个设备之间建立UDP通信,具体的STUN流程可以参考RFC5389,不在此赘述。

3. TURN

通俗的说,TURN(Traversal Using Relays around NAT)就是中继/转发,并不是所有的设备之间都可以依靠STUN来建立连接的,那么当两个设备之间无法依靠STUN建立连接时,就会启用TURN来进行数据中转。

由于我们的目标是节约带宽,如果采用TURN转发的话,并不能减少服务器的带宽消耗,另外一个原因是,在整个建立连接的过程中,有别于传统的视频通话只能1对1,这里的传输模式是1对多传输,所以并不要求每个连接都可靠,因此在H5 P2P项目我们仅仅通过STUN来实现连接的建立。

六、数据下载

1. 资源编码

Web P2P网络直播方案也可以同时支持任意多路直播同时进行,必须保证各路直播流之间的独立性,因此,我们提供一种统一的资源编码方式,用来标识唯一的一路直播流。这里主要借用直播流中的StreamId,通过计算MD5,生成固定长度的资源ID(RID),不仅保证了内容相同,清晰度不同,RID也不同;也保证了相同的内容,由于断流切换源地址,导致URL变化,保证资源ID(RID)相同。

2. 下载调度

在整个直播过程中,由于可播放缓存的数据是非常小的,通常不超过10秒?因此如何实时的根据当前的网络状态、网络环境,作出使用CDN,又或是使用P2P的决策呢?这里,我们的最佳实践主要如下:

a. 为了保障用户的观看体验,当缓冲区的可播数据低于某个阈值(例如5秒),就切换CDN下载

b. 当发现某一片未来的数据,周围的人都没有的时候,即使可供播放的buffer还有很多,不满足a策略的描述,这个时候,为了尽快的分发数据,也应该及时切换至CDN,出现这种情况时,往往表示这个节点以及他连接的节点都处于整个直播数据分发的顶层,为了防止出现 “一人下载多人围观” 的场景,本着更快的下载导致更早的上传理念,不仅仅要求该节点自身尽快CDN下载,同时也保证周围用户某个比例(例如15%)也尽快采用CDN下载,从而使得整体数据的分发效率提升。

3. P2P任务分配

a. 任务编号

对于每一个数据块都有一个自然数编号(sn),对于这个数据块,我们按照固定长度(默认16KB)的大小进行切分,简称chunk_index,那么(Rid, sn, chunk_index)就可以唯一确定一个数据片了。

 

b.分配请求

分配过程类似于扑克中的发牌机制,唯一的要求是对方这个节点拥有这个数据块,并且质量越好的节点,越多越分配靠近播放点的、重要的数据。下图简明扼要的展示了3个相同质量节点分配2个数据块(9个数据片)的过程。

image.png

4. 内存控制

对于Web P2P来说,所有的媒体数据都缓存在内存中,但是,也并不是会缓存完整的数据。对于直播来说,所有用户的观看点都是非常接近的,因此,内存始终缓存播放点前后的固定大小的数据。因为只有这部分数据分享利用率才是最高的。

image.png

如上图所示,有颜色的数据块都是当前在内存缓存中的数据,其中红色数据块表示当前的播放点,黄色数据块表示过去已经播放过的内容,绿色数据块表示未来还未播放的内容,可以看到当播放点从100移动至101时,97号数据块就被淘汰了,同时103号数据块作为最新的数据被下载下来并缓存到内存中。

七、工程实践

1. Goggle FlatBuffers

不管是服务器通信还是点对点的P2P传输均采用了FlatBuffers。FlatBuffers具有跨平台、内存和效率速度高,扩展灵活等优势,被我们全平台统一采用,大幅降低了通信成本。

2. 多浏览器兼容

线上支持WebRTC的浏览器不仅种类繁多,而且同一个产品的不同版本之间也可能千差万别。为了解决这一痛点,最终采用了WebRTC adapter.js来解决这一挑战。

3. 内存池

尽管Node.js自带垃圾回收机制,以及内存管理策略,但是GC和内存分配也是需要成本的,况且Web端是单线程环境,任何性能的提升都会减少时间上的损耗,进而可以处理更大吞吐的网络层传输以及业务逻辑。所以在内存分配上我们采用了内存池策略,基本实现了100%的内存重复使用。

八、技术结果

下图展示某次大型直播的带宽分时统计,显示在19:25到21:00阶段内的真实数据,随着人数的涌入和离去,Web P2P全程带来可观的带宽收益。最终评估Web P2P,在不影响用户使用体验的前提下,不仅可以有效降低服务器的负载压力,并且能够降低可观比例的带宽成本。

image.png

九、思考总结

目前,该技术已经大规模应用在各网络直播中,良好的解决了服务质量与带宽成本的平衡。但是,我们也发现在超大规模的直播下,存在了一些提升的空间,主要如下:

(1) coturn与MQTT的服务性能不高,会制约直播的服务质量。

(2) 接入边缘网络,打造多元化网络,缓解CDN负载,并且可以进一步降低CDN的带宽成本。

相关文章
|
20天前
|
前端开发 JavaScript 开发者
JavaScript:构建动态网络的引擎
JavaScript:构建动态网络的引擎
|
3月前
|
机器学习/深度学习 算法 量子技术
GQNN框架:让Python开发者轻松构建量子神经网络
为降低量子神经网络的研发门槛并提升其实用性,本文介绍一个名为GQNN(Generalized Quantum Neural Network)的Python开发框架。
67 4
GQNN框架:让Python开发者轻松构建量子神经网络
|
20天前
|
前端开发 JavaScript 开发者
JavaScript:构建动态Web的核心力量
JavaScript:构建动态Web的核心力量
|
5月前
|
前端开发 算法 API
构建高性能图像处理Web应用:Next.js与TailwindCSS实践
本文分享了构建在线图像黑白转换工具的技术实践,涵盖技术栈选择、架构设计与性能优化。项目采用Next.js提供优秀的SSR性能和SEO支持,TailwindCSS加速UI开发,WebAssembly实现高性能图像处理算法。通过渐进式处理、WebWorker隔离及内存管理等策略,解决大图像处理性能瓶颈,并确保跨浏览器兼容性和移动设备优化。实际应用案例展示了其即时处理、高质量输出和客户端隐私保护等特点。未来计划引入WebGPU加速、AI增强等功能,进一步提升用户体验。此技术栈为Web图像处理应用提供了高效可行的解决方案。
|
20天前
|
人工智能 监控 数据可视化
如何破解AI推理延迟难题:构建敏捷多云算力网络
本文探讨了AI企业在突破算力瓶颈后,如何构建高效、稳定的网络架构以支撑AI产品化落地。文章分析了典型AI IT架构的四个层次——流量接入层、调度决策层、推理服务层和训练算力层,并深入解析了AI架构对网络提出的三大核心挑战:跨云互联、逻辑隔离与业务识别、网络可视化与QoS控制。最终提出了一站式网络解决方案,助力AI企业实现多云调度、业务融合承载与精细化流量管理,推动AI服务高效、稳定交付。
|
1月前
|
机器学习/深度学习 算法 搜索推荐
从零开始构建图注意力网络:GAT算法原理与数值实现详解
本文详细解析了图注意力网络(GAT)的算法原理和实现过程。GAT通过引入注意力机制解决了图卷积网络(GCN)中所有邻居节点贡献相等的局限性,让模型能够自动学习不同邻居的重要性权重。
128 0
从零开始构建图注意力网络:GAT算法原理与数值实现详解
|
6月前
|
边缘计算 安全 算法
阿里云CDN:构建全球化智能加速网络的数字高速公路
阿里云CDN构建全球化智能加速网络,拥有2800多个边缘节点覆盖67个国家,实现毫秒级网络延迟。其三级节点拓扑结构与智能路由系统,结合流量预测模型,确保高命中率。全栈式加速技术包括QUIC协议优化和Brotli压缩算法,保障安全与性能。五层防御机制有效抵御攻击,行业解决方案涵盖视频、物联网及游戏等领域,支持新兴AR/VR与元宇宙需求,持续推动数字内容分发技术边界。
403 13
|
3月前
|
监控 安全 Go
使用Go语言构建网络IP层安全防护
在Go语言中构建网络IP层安全防护是一项需求明确的任务,考虑到高性能、并发和跨平台的优势,Go是构建此类安全系统的合适选择。通过紧密遵循上述步骤并结合最佳实践,可以构建一个强大的网络防护系统,以保障数字环境的安全完整。
88 12
|
4月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
4月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。