一、压测背景&目标
“又没有声音啦...”
“老师,你的画面怎么不动啦?”
相信这是每一个上过网课的同学都曾遇到过的场景。疫情期间,线上教学成为了当下教学活动中必不可少的一部分。但最令人抓狂的,就是上课过程中,学生突然掉线,教师共享画面卡顿或者延时。作为测试,要怎么及时发现这些性能问题呢?
在线上教学场景中,借助 NERTC技术,实现屏幕共享功能,共享教师的 PPT、文档甚至是视频内容给学生,再配合摄像头和麦克风,将教师的实时画面和课程讲解内容推送到学生端,这部分的内容,类似于“直播”、“线上会议”,对清晰度、流畅度都有较高的要求。与常规“直播”不同的是,教学活动中需要大量的“互动”,教学的本质即互动的过程。这些互动主要表现为丰富的场景,包括教师的板书、学生的抢答、收集观点、投票、随堂练习等。
当前所开发的智慧课堂系统包含教师端(Windows 应用),学生端(Pad)以及服务器等部分,当前设计容量为同一堂课最高容纳450个学生同时在线。线上教学的“直播”部分借助第三方 SDK 实现,而互动相关的主要功能,由“信使”服务实现。直播、互动这些丰富的互动形式以及多样化的数据通信需求,给压力测试带来了极大的困难。比如我们在进行常规的接口压测时,评估更多的是接口的响应时间、TPS、服务器的性能等,而这里则更多要考虑的是如何构造贴合用户的场景与环境,如何设计压测方案等。
为了保证教学效果,我们制定了一系列的评估指标,客观上,在线人数需要维持在合理范围内,即使掉线,能够快速恢复到最近状态,同时静止画面、动态画面的共享延迟不应超过 700ms。主观上,需要音画同步、双端清晰流畅无卡顿。如此,才能让网课的体验如丝般顺滑。
二、整体方案
如前所述,为了满足线上教学所需,系统整体设计与功能是较为复杂的,因此为了更方便的定位问题以及更快的执行效率,我们决定采用分步压测的方案,先分别对直播、互动进行压测,并在压测过程中关注各自的性能指标数据,待分别满足要求之后,再整体压测。整体的方案如下图所示。下文将从直播、互动两个方面分别对整体方案进行更详细的阐述与分解。
2.1 直播压测
(1) 压测环境构造
在直播相关的场景中,我们主要关注的是整个系统的稳定性、学生端视频流畅程度,以及音画同步质量。为了让压测效果更加真实可靠,我们需要首先构建一个 450 名学生同时上课的“直播”场景。在真实网课环境中,学生的网络环境是隔离分散的,而在测试过程中,显然并没有上百台真实的 Pad 供我们测试,即便存在,几百台设备的调度控制也是不现实的,而且处于同一局域网环境下,其测试结果也是不准确的。
通过调研,我们使用了selenium-grid (docker),借助其Hub-Node的分布式主从测试的方式,在K8S中,构建一个Hub主节点和若干个Node代理节点。Hub主节点用来管理各个代理节点的注册信息和状态信息,并且接受远程客户端代码的请求调用,把请求的命令转发给代理节点来执行。在具体压测实施过程中,共开启25个Pod副本,并在每个pod上开启18个chrome浏览器, 每个浏览器启动直播 SDK 模拟学生进入直播间。这样既解决了设备不足的问题,又借助 Rancher容器调度机制,充分利用了网络环境,最大程度上消除了因网络问题带来的结果的不确定性。
(2) 压测指标
直播需要很强的实时性,如果教师的行为和学生的响应无法同步,会给教学非常不好的体验,我们定义,同一事件在教师端发生的时间点和学生端收到该事件的时间点之间的差值为延时,通常情况下,该数值越小,代表端对端的实时性越好。为了测试实时性,我们用脚本生成了一段视频,视频的内容为从 0 开始计数的秒表值,同时视频的背景颜色随着时间的流逝不断变化。在教师端播放该视频,并将屏幕共享给学生端。这样不仅便于计算延迟,更能很直观地通过教师端和学生端颜色差异的大小来判断延迟情况。在测试过程中,每隔 1.5 分钟,给教师端和 Pad 拍照,并计算教师端时间和学生端时间的差值,持续观察 1 小时,得出最终的延迟数据,如图所示。平均延迟在 650ms 左右,而最大延迟约为 800ms,可以满足日常教学需求。
NERTC SDK 以辅流的形式实现屏幕共享,正常情况下 FPS 达到每秒15帧以上的视频流才能保证观看的流畅度,如果 FPS 低于15帧,则有明显的卡顿感。在测试的过程中,我们发现,在静态画面或 PPT 播放等场景中,双端实时性好,能满足业务需求。而在视频教学场景中,学生端接收画面卡顿明显,分辨率低,无法正常使用。通过分析,排除了CPU、内存等可能的影响因素,最终发现是教师端采样率设置不合理,导致学生端下行帧率低,加之网络丢包等因素,更加剧了这一情况。通过不断调整教师端采样参数与测试,最终达到了流畅度与清晰度兼得的效果,满足了视频教学场景所需。
2.2 信使服务
(1) 数据构造阶段
信使服务是教师端和学生端消息通信的"中转站",学生和老师能顺利在同一班级中上课,信使服务起着重要的作用。教师端登陆会向信使服务发送"建立Webscoket连接"的请求,成功后信使服务会向同一个Websocket通道中所有的学生端发送"教师上线"的通知。同样的,学生端建立连接后,教师端也会收到信使服务发送的"某位学生上线"的通知。
学生端和教师端进入同一个Websocket通道后,双方都会不断向信使服务发送ping消息来表明自己的在线状态,信使服务则会及时回应pong消息代表信使服务知晓客户端的在线状态并同时表明自身的存活状态。这样,信使服务就可以实时的知道每一个学生端和教师端的状态。在上课过程中,教师还会发送文章开头提到的课堂指令与学生进行互动,学生收到该些指令后会通过一些UI操作进行回应。比如:老师发送一个单项选择题的互动指令,学生收到该题目,在Pad端作答完成后提交自己的答案供老师检查。这就是一个完整的交互的例子。
在一个班级中,教师端发送一条指令,信使服务需要传达给每一个在线的学生,面对单班级450人同时通信的压测目标,我们的测试条件是非常有限的。我们既没有同时操作450台设备的人力,也没有450台真实的设备供我们使用,因此我们做了学生端的模拟工作,主要模拟的内容分为两部分:建立Websocket连接、响应教师端发送的互动指令, 以达到对信使服务模拟压力的效果。为了效果更加真实、配置更加灵活,对于教师端发送各种不同的互动的指令,学生提供了三种不同的反馈规则,分别是"随机"、"自定义"、"不响应",对于不同的学生可以配置不同的响应规则。
“随机”类型是指教师端发送互动指令时,被选中的学生一定会进行回应,但回应的内容是随机的。比如:老师发送了一道单项选择题,被选中的学生“文公良”一定会回答,但回答的内容可能是“A”、“B”、“C”、“D”中的任意一项。“自定义”类型是指教师端发送互动指令时,被选中的学生一定会进行回应,且回应的内容是预先规定好的。比如:老师发送了一道单项选择题,被选中的学生“尤时”一定会作答,并且无论发几个单项选择题,他的答案一定总是“A”。“不响应”类型是指学生只是保持在线状态,教师端发送互动指令时,被选中的学生不会进行回应。比如:老师发送了一道单项选择题,被选中的学生“广宗”不进行做答。
在压测时,我们在容器中创建了9个Pod,每个Pod部署开启一个规则,每个规则配置了50个学生,通过这种方式确保发压机可以游刃有余的进行调度,避免因发压机器CPU/网络模块占用过高,ping消息发送不及时导致的断连。到这里,我们就构造出了随时打开、随时停止、自定义响应内容、全流程监控通知的压测数据。这套模拟学生的工具不仅可以助力本次压测,还能推广到日常测试中使用,减少教师端的测试同学构造数据、操作学生端设备做配合的成本、也能方便产品及开发同学快速自测。同时为了配合压测,我们增加了对Mock出的学生端的监控,实时检测学生端的连接状态,统计在线人数,如果发生断连及时通知断连原因。
(2) 重连机制
按照业务要求,450学生需要稳定连接2小时以上,而在压测过程中,我们观察到,在连接约半小时后,学生端开始出现掉线的情况,甚至 1 小时后,全部掉线。
具体的断连现象包括:
- 现象一:开课10分钟左右,客户端收到了信使服务的close指令触发了Websocket断开,但信使服务端记录的日志显示是客户端主动发起的注销。并且在同一时间,我们使用Python的websocket-client / nodejs脚本 / 真实Pad 这三种连接方式都会发生断连;
- 现象二:学生端收到on_error指令,Websocket连接断开,报错信息为:[Errno 54] Connection reset by peer;
- 现象三:学生端Websocket连接断开,信使服务端显示该客户端已经从通道中被移除。
为了增强连接的鲁棒性,客户端与信使服务之间增加了“重试机制”:学生端正常连接过程中,如果多次ping收不到信使服务的pong或者收到了信使服务的on_error指令或者收到了信使服务的on_close指令,断连后都立刻进行websocket重连,直到重连一定次数仍无法建立正常连接时,才认为学生端网络异常/信使服务异常,才会真正的断开连接并在UI交互上提示用户手动重连。
客户端增加重连机制后,按照同样的逻辑修改了模拟学生端连接的脚本,增加了相同的重试机制及计次方式,保证脚本模拟出的学生端的真实性。增加重试之后,即使网络波动导致学生端断连,也可以在很短的时间内重连回来,可以明显的看到学生端连接稳定性的提升,学生端体验更加的丝滑流畅。
三、效果
在整个压测过程中,累计发现 50 多个各种各样的稳定性和功能性 Bug,经过开发和测试不断的努力,在上线前对所有的问题进行了修复和验证,性能指标也都达到了预期。
1.同步延迟:
对于动态画面,教师端和学生端的延迟控制在 600ms 左右,和常规直播的延迟标准持平,无明显音画不同步现象。
2.同时在线人数&掉线率:
单堂课同时在线人数最高支持 450 人,掉线率(掉线次数/成功建立连接次数)控制在 1% 以下,掉线恢复率 100%,平均掉线恢复时间为 3s。
3.清晰度:
双端画面清晰、流畅,无花屏、马赛克等现象。
4.流畅度:
主观上,教师开始上课,从大批量学生瞬时加入直播间,到教师可以流畅操作教师端,平均需要 1s 左右,与业内首屏 1s 左右的平均加载时长体验一致。上课过程中,各种互动操作友好流畅,无主观可感知的卡顿。
5.其他方面:
常规性能指标方面,各个服务运行稳定流畅,内存无明显增加,CPU 占用正常符合预期,无崩溃等情况发生。
因为整个的压测过程是完全模拟了用户情况,甚至比线上真实环境更加严苛,因此我们对系统“如丝般顺滑”的上课体验是充满信心的。服务上线后,老师和学生们普遍反馈上课过程流畅、互动丰富,整套系统受到了老师和学生们的一致好评。在整个压测过程中,积累了很多压测工具,也提升了压测经验,从面对压测任务的束手无策到游刃有余,是对业务加深理解的过程,更是对测试同学能力的提升。
TesterHome注:
在计算机科学中,鲁棒性是指一个计算机系统在执行过程中处理错误,以及算法在遭遇输入、运算等异常时继续正常运行的能力。