直播间场景下长链消息业务性能测试实践(一):APP客户端
本期作者
卢凯
bilibili资深测试开发工程师
2019年加入B站直播质量团队,现为直播专项质量团队和创新业务线质量负责人;先后主导落地直播质量工程、专项测试能力、流媒体测试体系建设。
背景和挑战
近年来B站直播业务飞速发展,从LOL S赛到“最美的夜”跨晚直播、传统节目拜年纪,高流量直播互动节目对直播间看端性能和质量提出了越来越高的要求。
直播的互动形态随着技术的迭代演进,由直播间内用户聊天互动的IM消息流衍生出礼物消息、进场、关注、购买、带货商品、连麦、付费留言等互动行为的实时提醒,这些丰富的实时交互能力都是通过长链消息流下发的。消息流可以认为是直播间内主播与用户间实时互动和直播间实时控制的基础能力,在B站直播业务统称这类消息流为“广播”。对比电商等传统C端业务,交互形态和信息承载会有明显的不同,下面以两个互动类场景举例。
直播:
-
直播间会承载更多的实时互动信息,成千上万观众实时的讨论和信息表达,会直接呈现给用户观看端。
-
更多酷炫的礼物特效、弹幕玩法、大航海动画等效果,构造出有趣热闹的直播间氛围。
-
用户沉浸式观看,长时间使用。
电商商品详情页:
-
聚焦重点的信息传递,用户快速认识了解商品,偏向静态信息触达。
-
商品-评论-详情-推荐,引导下单的价值传导,用户停留时间较短,主动操作获取信息展示。
直播间互动场景
商品详情页场景
基于上述的业务差异,直播业务相比传统C端场景更注重终端的体验和性能:端展示各类用户聊天和系统消息,一般一屏不超过10-20条;如果每秒有超过20条的消息下发,端上展示的消息基本会持续刷屏,结合直播互动礼物消息的特效等大量的消息,对端的处理和展示,带来持续高负荷。所以,对于一个长时间观看直播的用户端来说,如果出现持续的大量消息,端的消息消费会有显著的性能压力,且过多消息会有累积效应。
如上图所示:当前直播间同一时刻会存在弹幕、续费提醒、进场提醒、全屏礼物动画、连击礼物、付费留言等,如果此时终端性能无法跟上,丰富的玩法和特效反而会拉低用户体验,对营收促进效果也会大打折扣。
我们将直播互动能力进行抽象,划分出9大互动区域:
直播间互动能力抽象
互动能力性能体验影响分析
我们在针对上述实时互动能力的测试实战中遇到了以下质量保障难点:
-
场景构造链路太长:测试各类广播在直播间效果以往的手段需要多端配合且依赖账户数据,以触发大航海特效为例:首先需要使用推流工具使直播间开播,终端A登录账号进入直播间送出礼物,终端B进入直播间,A、B分别收到主客态广播,触发礼物特效。整个场景构造链路长且冗余,耗时耗力;
-
异常数据构造能力缺失:广播内容完全由服务端下发,无法模拟各个字段的异常情况,广播容错测试处于完全空白;
-
性能测试效率低下:针对广播测试,传统的端到端功能维度去测试,不能解耦开来,缺乏对端的消费能力、性能、体验进行针对性测试,临近大型活动,都需要投入大量人力进行手工回归,且卡顿、闪退、发热等体验问题频发;
-
测试资产复用困难:直播的广播消息类型经过数年迭代,有超过100+的消息类型,测试资产积累基本靠文档相传,复用艰难。
每当有大型活动时,上述终端质量保障难点问题因为直播间流量的放大会变得尤为突出,而我们如果需要进行全面的保障,需要额外投入大量的人力、物力和精力。面对越来越复杂的业务,其可测性、提高保障效率成为了极大的挑战。我们不断地思考该如何取得平衡。最终完成了一套面向终端消费场景的直播间广播压测工具链并平台化-广播压测平台,大幅提升了直播间整体质量与专项测试效率,并沉淀下来直播间复杂广播场景下性能测试的最佳实践。
广播压测系统架构图
解决方案
根据测试工作流,我们将平台拆分为消息元数据收集与管理模块、压测及任务配置模块、发压服务、性能采集模块与报告服务。
1. 广播消息元数据收集
广播能力作为互动基础能力,直播技术团队积累了多个收集渠道,我们可以从可视化监听工具tool live message lisenter,python实现的BliveClient及广播消息文档中获取广播消息体结构,同时可以手动改变广播体中部分字段的内容、变量类型、结构等,方便造异常数据,通过case管理页面进行归档,使得用户通过自定义标签管理。
tool live message lisenter
case元数据归档及自定义标签
为了能仿真模拟线上直播间互动场景、提供更丰富APP线上异常排查的手段,我们通过对broadcast-proxy广播日志的全采样,经过decode预处理、时间戳正排归档为有序的广播回放文件,可以在压测配置时直接使用。
流量回放文件
2. 压测任务配置及场景编排
直播间压测需要根据业务&技术改造场景,能自由配置不同组合及QPS,我们设计上使用消息结构体的CMD字段作为队列ID,每个队列中可以自由放置多个case。
压测配置
平时测试同学会根据单次的需求内容定制一份对应配置随着压测配置,形成了一个单元场景。但随着case与配置的增多(配置有超过350+,case超过1000+),这些单元场景的复用&组合成为了测试同学的一大困扰。因此我们在配置基础上,又设计了一套单元场景组合的结构,通过将配置以多对一形式映射到任务,完成单元场景的复用。
单元场景组合&复用逻辑
配置场景队列
3. 发压服务
完成了cmd case到task的四层数据分层后,我们如何按照设定的QPS发压呢?
我们目前是自己实现的一套发压能力,以压测配置的单元场景举个例子:压测配置A我们添加了两个数据队列,每个数据队列都可以配置对应的发送QPS,SEND_GIFT队列中有5个case,DANMU队列中有3个case。
收到发压指令后,发压服务会分为3个阶段进行发压:
-
启动一个1s的定时loop,为A队列分配一个线程A1
-
线程A1会从对应队列中随机取出QPS数量的case存入buffer
-
线程A1将buffer中的数据通过调用broadcast-proxy服务下发到客户端,发送完成线程销毁。
压测模块架构
不难发现,目前这个实现方案还比较粗糙,QPS是不完全准确的,受限于响应耗时,QPS过高的配置会失真。发压的逻辑和性能优化非常复杂,后续我们考虑使用专业性能工具作为底层依赖来优化发压能力。市面有包括Jmeter、Locust等优秀的开源工具,经过一些桥接设计是可以做到满足业务场景诉求与发压逻辑优化的。
4. 性能数据收集
经过调研,我们选择了perfdog作为app端的性能采集工具,有以下优点:支持Ios/Android双端、采集数据全面、支持自定义报告上传等。
5. 报告服务
报告服务通过perfdog的report接口协议,设置客户端 upload server,测试数据上传至后台归档,实现性能数据私有化。如下图是针对压测过程中各项数据的归档,可以实现多版本性能基线统计,为性能防劣化与场景对比提供分析能力。
数据归档
实操经验分享
我们以APP性能治理实践经验和工程实践过程重的一些创新型优化作为举例。
1. APP房间页性能压测实践:
以2020拜年纪客户端性能保障为例
根据实际保障的业务特性,我们首先制定压测目标:
-
中高端机型在高于预估压力的情况下2小时播放流畅,不出现崩溃、闪退、无响应。
-
低端机型在高于预估压力的情况下2小时播放保活,不出现崩溃、闪退、无响应。
压测场景
制定分级测试策略
根据活跃用户使用机型市占率,我们与研发一起将机型进行性能模型分层。
设备分级模型
根据保障场景配置压测数据
拜年纪是高弹幕互动场景,不是高消费活动,业务也会要求屏蔽引流类型的特殊广播消息,所以我们将弹幕case配置的case数量与QPS高一些,补充小型连击礼物,来尽量模拟贴近真实场景。
配置实践
性能报告分析
总结来说是分析拐点和趋势。从memory和fps可以看到有一段数据空白,出现闪退,同时整体内存趋势一直上涨,是明显不合理的,说明有不可见资源引用对象或其他大对象出现了内存泄漏。
iPhone6测试数据
经过日志分析出现线程切换过多导致被watchdog kill。
Wakeups: 45001 wakeups over the last 251 seconds (179 wakeups per second average), exceeding limit of 150 wakeups per second over 300 seconds
根据业务场景分析,对终端广播处理作出相应优化:
1. 老旧机型频繁线程切换的队列合并
根据苹果相关分享,针对GCD队列使用场景较多的场景,可以使用dispatch_set_target_queue优化线程的创建和调度,规避线程切换过多导致的crash
2. 低端机型socket弹幕日志屏蔽,规避json转换的性能问题
3. kv配置:使用ios弹幕出口速率(live_ios_danmaku_cache_rate)控制队列长度
日志线程优化核心逻辑
4. 避免弹幕队列引用ViewModel造成延后释放
优化引用逻辑
2. 日志回放出现较大时间累计偏差
我们在第一版设计的时候参考TcpReplay、Goreplay,通过计算录制报文的第i 个报文与第i-1 个报文的间隔来控制回放报文的发送。通用定时器由于非实时性操作系统的任务调度机制都会产生ms级别的误差,每条数据发送延迟在 0~10ms 间波动。由于每一条数据发送时间偏移均基于上一条数据发送完毕的时间点,因此持续执行会将数据延迟记录叠加,最终导致总延迟放大至分钟级别,经测试,50条数据误差在 150ms 左右,20000 条数据误差在 2min 左右。这种方法会使误差逐渐累积,进而导致在回放流量逐渐增大时,回放的逼真度会逐渐降低。
后续我们优化了一版基于首条偏移量纠正的回放算法:
回放算法
图中左边是在日志预处理和日志排序中,从日志中提取的各个数据发送的时间戳(实际发送时间),该算法是根据各数据实际发送的时间戳确定日志个数据回放的时间,即前面第0到k条数据已经回放完毕,通过计算timeStamp k与timeStamp 0之间与回放数据的时间偏移,来纠正K+1的时间偏移,从而确认K+1的回放时间。
经上述优化后,实际每条数据发送时基于首条发送的时间偏移量与预期之间误差小于 10ms(与发送总量与总时间无关,不会导致偏移累加),达到预期效果。
广播压测平台在APP客户端
性能测试的落地效果
作为直播质量保障常态化手段和能力,测试资产积累超过500+case,300+压测配置,执行超过4000+次压测任务。
结合monkey测试等累计发现超过100+卡死闪退等严重性能bug,发掘超过450次内存泄漏问题,保障包括S10、S11、“最美的夜”跨年晚会等的年度爆款大型活动,实战高压互动场景下性能稳定运行。
经过与研发持续协作优化打磨性能问题后,在超负荷广播消息下发压测场景,双端APP在关键性能数据都有数倍提升。
专项治理效果
APP客户端只是长链消息下游的其中一个部分,web端用户在直播业务比重依然很高,受限于篇幅,我们之后会分享web端保障的实践经验。
- 没有SLO就没有SRE?来看看B站SRE对SLO的实践总结(下)
- 元宇宙?Web3!智能合约设计与工程化实践
- 全链路压测改造之全链自动化测试实践
- B站基于Apache Ranger的大数据权限服务的技术演进
- B站移动端低代码测试探索与实践
- 直播间场景下长链消息业务性能测试实践(一):APP客户端
- B站压测实践之压测平台的演进
- 基于 Bazel 的 iOS Monorepo 工程实践
- 红队视角下的容器逃逸利用及分析
- 哔哩哔哩应援弹幕
- 开放平台视频投递流程的演进与思考
- B站离线计算的实践
- B站大数据平台元数据业务分享
- ViGA:一种介于强弱监督之间的视频片段检索范式
- 哔哩哔哩Android编译优化
- B站基于AIFlow Flink在批流融合调度上的实践
- 哔哩哔哩在Hilt组件化的使用 | 技术探索