⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 wangyapu.com/2020/05/27/barrage_arch/ 「王亚普」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前言

直播业务现在特别火爆,也给人们的互动方式带来了很多新的改变,比如刷礼物、弹幕、排行榜等等。面对巨大的流量规模,直播技术的发展也备受关注。作为一个技术爱好者,相信你也会对直播的技术比较感兴趣,于是我去翻了几篇文章,了解了直播的技术方案,发现涉及到的技术细节太多,有部分已经是知识盲区,如音频、视频的编码传输等。

斗鱼:如何打造一个高性能、高可用直播系统架构

蘑菇街直播架构

直播相关知识之一-基本架构

直播中弹幕是一个非常亮眼和重要的功能,相比于秒杀架构,直播弹幕系统也有很多有趣的知识可以挖掘,一起来 YY 下如何设计一个直播弹幕系统,不对的地方还请有经验的大佬指出。

直播弹幕系统

直播弹幕是一个读写 QPS 要求都很高,假设一个直播间有 100w 用户同时在线观看,假设弹幕的提交频率为有 10000条/秒,那么需要每秒同时推送给在线用户的次数为 100w * 10000。由此可见,读请求的吞吐量需要远大于写请求,这点类似于 IM 实时聊天。、

架构设计考虑以下几个场景:

  • 支持直播弹幕回放
  • 用户进入直播间可以推送最新几秒的弹幕数据
  • 长连模式和短连模式可以做降级切换

MVP版本

为了不影响读写的性能,采用读写分离架构。

  • 写服务:若不考虑历史弹幕可回放,可以直接使用 Redis 作为唯一存储。若考虑支持弹幕的回放,数据还是需要持久化,可以考虑使用 MySQL 或者 TiDB,暂且认为写入不是较大的瓶颈。如果有更高性能的写需求,HBase、OpenTSDB 等都可以解决问题。
  • 读服务:Redis 主要用于读缓存,缓存直播间最新的弹幕数据,采用直播间 ID 作为 Key。系统读服务最大 QPS = Redis 集群QPS。

Redis 存储结构选择:SortedSet。

  • 提交弹幕:ZADD,score 设置为时间戳。进一步优化可以只存储时间的 delta 值,减少数据存储量。
  • 弹幕查询:ZRANGEBYSCORE 定时轮询弹幕数据。

有什么问题?

  • 系统性能与 Redis 集群容量强相关,性能提升需要扩容 Redis,成本高。
  • Redis 重复请求较多,相同直播间会存在很多重复的轮询请求。

缓存优化

如果能让最新的实时弹幕数据都能命中本地缓存,那性能是最高的,同时大幅度降低了 Redis 的读取压力。所以弹幕读服务可以每秒轮询 Redis 数据,构建本地缓存。

热点问题:

  • 假设同时在线的直播间有 10000 个,读服务机器有 50 台,那么每秒轮询 Redis 的 QPS = 10000 * 50 = 50w,读取请求线性膨胀。
  • 本地内存的使用量也随直播间的数量增长而膨胀,每个直播间的缓存的数据量降低,导致本地缓存的命中率降低,容易导致 GC 频繁。

热点优化

如何降低本地缓存的使用量?

  • 因为火爆的直播间会占据整个平台大部分的流量,可以只针对火爆的直播间开启本地缓存。
  • 通过路由控制同一个直播间的请求分发到固定的几台机器,例如一致性 Hash 算法。通过减少读服务机器上的直播间数量,达到降低本地缓存使用量的目的。

上述方法可以有效地解决问题,但是不能解决流量不均衡的问题。不同直播间分配的机器资源不是拍脑袋定的,需要有理论依据,可以根据直播间的一些数据指标进行动态分配机器资源。

  • 增加对直播间数据指标的统计,如单机 QPS、集群 QPS、单机直播间在线数等。
  • 关于自适应的负载均衡又是一个可以深挖的话题,在这里我们讨论几个常用的方案,有可能结合起来使用效果更好。
    • 分桶:不同 QPS 的范围段划分为不同的桶,根据桶范围的不同分配的机器数量也是不同的。
    • 最大最小公平分配:根据直播间的 QPS 划分资源需求的权重比例,根据总机器的数量和权重比例来分配机器数量。
    • 启发式算法:遗传算法、蚁群算法等。

单元化架构

单元化可以说是解决性能容量以及容灾的杀手锏。实现单元化需要完成有很多重要的工作,如数据同步 DRC、流量调度等,在此不作展开。

推荐一篇携程的 DRC 实践:携程异地多活-MySQL实时双向(多向)复制实践

客户端长连接推送

为了保障客户端消息的推送性能和实时性,长连接基本是必备的,最新的消息可以直接采用长连接实时推送。

  • Push Server 从 Redis 中获取用户和直播间的订阅关系以及长连接信息。
  • 连接代理只负责与客户端保持长连接。
  • 海量的消息推送需要批量压缩。

弹幕回放

增加一组专门用于回放的 Redis 集群,同时增加回放的本地缓存,其余设计与上述方案保持一致。

总结

抱着学习的心态,思考了直播弹幕系统的架构应该如何设计,本文主要讨论了以下几个点:

  • 读写分离的架构设计
  • 通过缓存优化读性能
  • 通过路由规则解决直播间流量不均衡的热点问题
  • 长连接的方案设计以及客户端的消息推送

暂时就 YY 这么多吧,做好一个系统还有需要细节需要考虑:高可用、监控、限流降级、延迟优化等。有什么错误和好的实践经验跪求留言。

文章目录
  1. 1. 前言
  2. 2. 直播弹幕系统
    1. 2.1. MVP版本
    2. 2.2. 缓存优化
    3. 2.3. 热点优化
    4. 2.4. 单元化架构
    5. 2.5. 客户端长连接推送
    6. 2.6. 弹幕回放
  3. 3. 总结