记录一次直播系统的分析和设计
产品功能简介 面临的技术挑战
技术选型及依据
架构设计方案
01 产品功能简介
1、答题以活动的形式展开,每场活动都会预先公布直播开始时间、答题总奖金、红包雨奖金等信息。
6、其他功能:邀请新人、活动榜单、奖金提现等。
1、直播的基础功能:连麦互动直播(支持多码率、多协议,多主播同框)、美颜、弹幕、IM聊天、点赞、屏幕共享等功能性需求,以及防盗链、涉黄涉政鉴别等非功能性需求。
2、应用本身的个性化功能:比如答题场景中的发题目、作答、公布答案,电商场景中的商品展示、一键下单购买,网红直播场景中的礼物打赏。
02 面临的技术挑战
当时我们做直播答题应用时,面临以下技术挑战:
1、音视频处理及传输:涉及音视频编码、实时美颜、视频推流、CDN加速分发、终端适配和播放,流量统计等诸多技术点,而且我们当时的技术团队没有专门做音视频方面的专家。
7、对商城交易业务的低干扰:直播答题仅作为商城的一个运营活动,核心目标是导流,它依托商城原有的用户体系,运营系统,大数据系统,提现通道等,如何做到对商城现有交易系统的低干扰?
可见答题这种泛娱乐的直播场景还是有挺多技术挑战的,它取决于直播应用的用户量级和业务流程。就算是直播电商这种低频交易转化的场景,要是李佳琪在带货,同样也会面临瞬时抢购的高并发挑战,所以架构设计时必须考虑业务高峰时的压力,并且系统的各个环节必须具备动态可伸缩的能力。
03 技术选型及依据
一. 音视频处理及传输的方案选型
音视频处理及传输,因为技术团队不具备这方面的能力,所以当时调研了各种云厂商的付费解决方案,终采用了腾讯云的直播解决方案。主持人侧:通过演播室的专业摄像设备,搭载腾讯云提供的obs推流软件,即可进行视频录制和推流。用户侧:APP端集成腾讯云的SDK,动态拿到推流地址后即可观看直播。
业务数据是指除音视频以外的,和答题应用场景相关的数据(比如题目、答案、弹幕、红包等)。腾讯云提供了两种可选方案:
1、题目预先设置好,直接由腾讯云的SDK通过音视频通道下发,打入直播流中。
2、让题目先通过腾讯云的IM通道快速送达观众端APP,在观众端先缓存下来,等待播放器通知了预期的 NTP 时间戳之后,再把题目显示出来。
1、Netty:Netty是当时流行的高性能和异步NIO框架,直播答题的业务场景中,涉及到题目下发、弹幕、下红包雨等非常多的推送场景,而且一场答题活动中,客户端和服务端的通信频繁,长连接比短连接在性能上更优。
2、ProtoBuf:作为客户端和服务端的数据交换格式,PB是一种效率和兼容性都很的二进制数据传输格式,在码流和序列化速度上明显优于JSON、XML、hessian等主流格式,同时支持向前向后兼容以及各种主流语言。
3、WebSocket:是 HTML5 一种新的协议,用来实现客户端与服务器端的长连接通讯。
04 架构设计方案
上面是腾讯云直播解决方案的架构图,其他云厂商(比如阿里云)的直播解决方案,技术架构类似。感兴趣的同学可以直接去腾讯云官网上详细了解,这里不做展开。
音视频流采用了腾讯云的直播解决方案,而业务数据流(活动、题目、答案、弹幕、红包等)则采用了自研的长连接方案。架构图中的答题系统和答题运营后台也均为自研。客户端会分开处理两个通道的数据,以控制用户交互上的变化。
三. 基于TCP长连接的通信架构
上面的通信架构用于业务数据流的传输,流程如下:
1、客户端使用websocket与服务端进行通讯,用户进入答题直播间时建立连接,退出直播间时断开连接。
2、Nginx对websocket做负载均衡。
3、TCP网关基于netty实现,用于维持长连接和转发业务请求,不负责具体的业务逻辑,它和下层业务系统(答题系统)通过RPC接口进行交互,主要考虑后续其他业务可以复用TCP网关层,所以将业务下沉。客户端和网关之间通过心跳机制保证连接的有效性以及检测僵尸连接。
4、消息推送(比如弹幕、下发题目、公布答案等诸多场景)由下层业务(答题系统)通过MQ通知TCP网关,再由TCP网关推送给客户端。
通信架构中另外比较重要的是数据传输格式的定义,客户端和TCP网关之间,TCP网关和答题系统之间均采用的是protobuf格式。下面分开说一下比较关键的几个格式定义。
4.1 客户端请求消息的格式
1、消息类型标识:-1表示心跳消息、0表示用户验证消息、>0 表示业务类消息
2、用户ID:用户的标识,在前置的登录流程中已经获得
3、Token:用户登录APP后的授权令牌,在前置的登录流程中已经获得
4、BizData:真正的业务数据,protobuf序列化后的byte数组,由下层业务自行定义更具体的格式
4.2 客户端响应消息的格式
1、消息类型标识:和请求中的消息类型保持一致
2、状态码:0表示处理失败,1表示处理成功
3、BizData:真正的业务数据,如果状态码为0,该字段为4字节的异常码(100表示token验证失败,101表示请求业务层失败),如果状态码为1,该字段为业务层返回的protobuf序列化后的byte数组,同样由下层业务自行定义更具体的格式
4.3 业务数据的ProtoBuf格式定义
1message Message
2{
3 MessageType messageType = 1; // 消息类型,枚举值
4 string sequence = 2; // 消息序号
5
6 Request request = 3; // 请求类消息
7 Response response = 4; // 响应类消息
8 Notification notification = 5; // 推送类消息
9}
1、网关层:架构上同时采用了TCP网关和HTTP网关,TCP网关上一章节已经讲解,它主要用于维持百万用户同时在线,以及答题期间的实时数据交互(包括加入直播间、推送题目、答题、推送答案、抢红包、弹幕推送等)。HTTP网关为APP端提供Restful接口,用于低频的数据请求,比如活动首页、排行榜、个人奖金明细、新人邀请、分享等场景。
7.1 答题接口的高并发设计方案
答题接口的并发预计20W QPS,在说设计方案之前,先简单列一下答题接口的判断逻辑:
1、需要判断答题活动是否仍在进行中
2、需要判断用户是否已经答错出局
3、需要判断用户输入的题目是否是当前正在作答的题目
4、需要判断用户上一道答对的题和当前这题是否连续
5、需要判断用户作答是否已经超时
6、需要判断用户的答案是否是正确答案
7、如果答错了,需要判断用户是否有复活卡
8、如果有复活卡,需要判断前面的题是否用过复活卡了
4、调整判断逻辑的顺序,上面提到的8个判断逻辑,其中前4个都属于安全校验,因为客户端已经通过交互做了拦截,如果用户不采取作弊手段肯定都能校验通过。所以我们将第5、6、7步逻辑做了前置,通过后再进行前4步校验,这样大大减少了计算量。
2、用户的作答结果也在第1步计算完成后立刻推送给用户了,不用等到主持人口播公布答案的瞬间,否则的话仍然涉及到并发读取作答结果以及有状态推送,对存储服务器以及带宽的瞬时压力仍然存在。
3、但是作答结果如果提前推送给客户端必然存在安全问题,黑客抓包就能提前知道是否答对了,可以利用批量账号进行作弊。为了解决这个问题,我们对作答结果采用XOR进行了对称加密,同时将秘钥延迟到公布答案的瞬间才下发,而且每道题的秘钥均是随机生成的。这样就很好地解决了安全问题。
4、公布答案的瞬间,我们只需要推送一个非常小的数据包给客户端即可,而且这个数据包所有用户都是一样的。
7.3 抢红包接口的高并发设计方案
屏幕下红包雨,用户触屏点中红包就直接拆了,所以抢红包接口的并发非常高,1秒内单个用户可触屏发起4-5次抢红包请求,按照百万用户在线,并发大可达到上百万QPS,下面说下技术方案:
1、红包金额提前计算好并加载到redis中:在创建活动时,运营可配置红包总金额以及红包总个数,系统在创建活动时就会提前计算出各个红包的金额并存储到redis中,相当于计算前置。
2、客户端限流:在接口设计时,我们就预埋了一个限流因子参数,可由服务端动态控制客户端的限流比例,在通知客户端抢红包的接口中,我们根据当前的在线人数以及红包总个数动态算出限流因子,控制多只有10W QPS的请求能发到服务端。
3、服务端限流:根据服务器数量以及红包总数量提前计算出每秒令牌的生成数量,基于guava的RateLimiter进行二次限流。
4、前面3步基本把并发降下来了,再通过lua脚本保证原子性即可,抢红包的结果也是在活动结束后再异步刷新到数据库。
7.4 其他高并发的优化点
1、Redis缓存的对象要尽可能简化(用不到的字段不要存),key的长度要尽可能短(高并发下的瓶颈在于IO),善于利用pipeline组装多个命令(但是命令个数不能过多)
2、各种连接池和JVM参数的调整:涉及redis连接池、dubbo的线程池、JVM内存大小,可以在压测环境下找到合理值。
3、答题系统可水平扩展(scale out),同时通过dubbo的分组配置将ToB和ToC接口进行隔离部署,避免相互影响。
相关文章