技术复杂度
对于一个直播间(头部主播):
- 在线人数100w
- 弹幕频率 1000条/秒
那么服务端推送频率就是:100w * 1000条/秒 = 10亿条/秒
如果是N个直播间,那么推送频率是:10N亿条/秒
方案对比:拉 vs 推
(客户端)拉模式
(服务端)推模式:基于websocket协议,可以看Web端通信-websocket协议(已整理)了解ws协议。
语言技术选型
NodeJS:
- 单线程模型。需要遍历非常多的用户集合,性能有限,不适合做推送。
C/C++:
- tcp通讯、ws协议实现成本高,需要diy
Go:
- 多线程,推送性能高
- 基于协程模型,能实现高并发
- websocket是标准库,无需要其他社区库
技术难点和解决方案
内核瓶颈与优化
优化方案:
服务端将一秒内的n条消息,合成一条消息推送
实现思路:弄个消息队列,每隔1秒来扫描它,然后将消息队列中积累的数据依次发送给客户端
合并后的效果,每秒的推送次数只等于在线连接数
锁瓶颈与优化
优化方案(GoLang下,可以利用多线程模型提高遍历性能):
- 大锁拆小锁,不上全局锁:将用户连接打散到多个用户集合中,每个集合有自己的锁
- 多线程并发推送多个用户集合,提高遍历性能,避免锁竞争
- 读写锁取代互斥锁:多个推送任务都可以同时获取某个用户集合的读锁,然后遍历它们进行推送
CPU瓶颈
优化方案:
- json编码前置:不用每次推送都推送json格式,在推送前,将json进行编码,之后的推送用编码后的数据,避免百万次重复编码
- 消息合并前置:N条消息合并成一条消息后,大包数据只需要编码一次
分布式架构
单机架构图:
单机瓶颈:
分布式架构图(这图画的是真丑):
gateway网关集群:就是前面实现的服务,他们负责将ws数据推到对应的连接上。
logic逻辑集群:用来接收自家客户端业务发来的ws数据,然后将他们广播给网关集群。
业务方和连接:业务方连接连的是gateway服务,用来接收数据;但是发送ws数据走的logic服务。
总体思想:接收消息和推送消息分为2个集群,不放在一个服务中。
弹幕系统前端设计
核心点
- 使用等待队列来存储弹幕消息,定时消费
- 使用Pool池化技术来避免多余dom节点浪费
- 对于过多的消息,直接丢弃
代码
1 | interface IDomContainer { |