QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

作业帮直播间前端架构优化实践

  • 2022-06-22
  • 本文字数:3266 字

    阅读完需:约 11 分钟

作业帮直播间前端架构优化实践

背景介绍


作业帮的直播间以信令为基础做教师端,学生端的同步渲染。整个直播间包括推拉流,流媒体渲染,聊天区,课件区,连麦, 通用互动等功能,其中课件区包括 H5 课件、Cocos 课件、白板、互动题、小游戏等。整体课件区内容的呈现是在 Webview 里,Webview 运行时聚合了多个不同种类的内容。下图为作业帮直播间功能简图。


技术难点


  • 终端碎片化带来多种内容渲染的稳定性;

  • 直播间性能保证,整体内存 /CPU 控制,子功能模块内存 /CPU 分配;

  • 信令到达保证及各个环节的有序执行;

  • 容错,任一内容环节出问题,如何保证不影响后续运行;

  • 不同技术栈内容的持续性接入。

现状


前面介绍了整个直播间多背景知识以及前端的一些技术挑战,前端的主要功能区在课件区,可以看下优化之前的老架构,对整体有个粗略的认识。



所有的业务层代码聚合在称之为 zb 的模块,从图中可以粗略看出 zb 模块是一个比较庞大的模块,承载了众多不同技术体系的内容渲染和调度,也是反馈问题的重灾区,运行在一个常驻的浏览器之上。

随着用户规模的不断增大,不同的用户机型设备的增多以及内容的丰富度和效果的提升,我们的 zb 稳定性以及性能遇到了很大的挑战,线上的工单反馈也有上升趋势。来自用户侧反馈的问题大概为以下几类:


  • 课件区黑屏,白屏,花屏;

  • 卡在某一个具体的页面,中断了同步;

  • 卡顿;

  • 互动题做不了;

  • 看不到老师笔记。

问题分析


通过大量的测试以及问题排查列举出我们的架构存在以下问题:


  • Webview 内存占用持续上升,无法及时 GC,内存不足是导致黑白屏的根本原因,Webview 的回收机制对我们来说是黑盒,尤其是基于 DOM 方式的渲染,研发无法通过代码触发 GC;

  • 卡顿的原因来源于一些动画造成 CPU, 内存瞬间增长;

  • 信令全链路到达有丢失,服务 -> NA -> Webview ,NA -> Webview 通信没有机制保障,兜底保证通信代码较多,即使信令到达,执行的时机以及完成时机都有一定程度业务的耦合;

  • 渲染不同内容的调度逻辑耦合较多业务逻辑,逻辑链路较深,排查问题较难;

  • 任一内容的逻辑出错或者报错有可能影响后续信令处理和调度逻辑;

  • 统一运行在同一个 Webview,不同内容的消耗很难通过指标进行量化;

  • 课件区内部分层不清晰,耦合较重;

  • 排查问题与不同角色的技术,边界不清晰,沟通成本高,排查效率低。

设计目标


根据直播间的面临的技术难点以及结合我们目前架构所面临的问题,我们希望新架构能够实现以下几个目标:


  • 底层保证内存及时回收;

  • 底层渲染 Runtime 可切换;

  • 通信可靠性保证(NA/FE);

  • 内容隔离;

  • 调度逻辑与不同内容解藕;

  • 单个内容针对性降低内存 /CPU 并且可量化

实践 & 探索


作业帮直播间的前端架构

容器及 SDK 设计

容器设计


容器的定义


容器是直播间任何内容的载体,容器可以是 Native 容器,里面运行着 Native 的组件,可以是一个 Webview 容器,可以是一个 Cocos 容器。容器有以下几个特点:


  • 载体;

  • 独立无依赖;

  • 生命周期;

  • 独立开发,独立部署。


有了容器之后,我们可以把调度逻辑独立出来,下沉到端,这一层可以更专注任务的调度以及信令的处理,与内容解耦。


容器的状态


容器 SDK 设计


有了容器的抽象,各个内容如何集成到容器内以及如何感知容器的不同的状态切换,需要一个标准 SDK 去帮助封装所有的底层细节,对业务无感。SDK 需要具备以下能力:


  • 生命周期钩子;

  • 支持自定义调试;

  • 支持后续的扩展;

  • 基础工具库。


可以通过下面这张图,简单了解 SDK 的容器周期和实现逻辑:


内容播放器


有了容器以及调度,作为内容的业务开发,可以更专注于某一个内容本身,为了保证后续内容的可持续规范性接入,我们针对不同的内容做了一层抽象,定义为内容播放器。我们的主要播放器有 H5 PPT 播放器,H5 互动题播放器,Cocos 课件及互动播放器,画版播放器等,下面会重点介绍下 H5 PPT 播放器以及详细介绍下 Cocos 播放器架构层面的一些优化方案。

H5 PPT 播放器


这里我们以 H5 PPT 为例来介绍基于新架构播放器的分层,H5 PPT 是由编辑器生产出一份数据 + 资源去驱动内容及动画的展示,参考下图,自底往上分别为: 


1. 容器层,负责播放器运行时;

2. 前端的基础库; 

3. 适配层, 播放器纯渲染层和直播间的适配,包括容器生命周期的桥接,信令的注册与处理 ;

4. 播放器的渲染层。


Cocos 内容播放器设计与优化


Cocos 内容播放器是比较复杂的一个播放器,代码量非常庞大,接下来会重点介绍下我们针对 Cocos 播放器结合新架构做的一系列优化。


当前问题


  • 信令恢复不稳定容易出问题;

  • 加载和恢复性能差,耗时久;

  • 线上问题排查困难,不易锁定。


问题分析


  • 依赖过程的同步同步逻辑,如果出现信令丢失或者信令顺序错误,则会造成逻辑错误,并且后续的所有操作和渲染逻辑都会受到影响;

  • 每次加载 Cocos 引擎、Framework、互动内容都会消耗大量的加载时间,同时依赖过程的恢复逻辑类似于帧同步,决定了断线恢复的时候要恢复之前的所有逻辑,耗时较长,CPU 占用较高;

  • 同步逻辑是同步的 Touch 事件派发,所以数据中的事件表示不出业务逻辑,只有客户端响应后才知道触发了何种逻辑。


解决方案及技术难点


  • 重构信令恢复机制,改为状态同步,状态同步可以解决数据错乱和丢包造成的结果不正确问题,以及恢复时耗时的性能问题,同时排查线上问题也能有明确数据内容来锁定问题。但状态同步有两个问题需要解决:与业务解耦和同步的数据量;

  • 加载性能和内存问题,一个通过采用 Runtime 提前初始化,另一个采用生产时对内容进行标准化限制。


状态同步设计


设计思路:底层捕获输入事件以及渲染数据变化,避免业务感知同步逻辑,状态数据的同步与业务逻辑解耦,降低研发成本,同时增加增量状态和全量状态两种数据,来解决数据量大的问题。

下面这张图是节点状态变化的捕获和分发流程,这个机制在多个端之间也可以正常运作,比如从 A 端捕获的状态派发给 B 端,这就满足的主讲的操作可以同步到学生端的诉求。



下面是状态数据量的优化策略,虽然全部数据已经通过上面的逻辑控制的比较低了,但是为了更高效,并不是每帧都同步全部数据,是在关键帧把数据同步,其它帧只同步增量,这样既保证了数据量也保证了准确性,即使有丢失错乱,但是在下次全量数据是也一定能够恢复正确状态。


内存和 cpu 优化


上一部分容器的抽象,容器可以被调度,可以被销毁,在一定程度可以保证渲染内容的及时回收,接下来这部分针对不同内容做的一些优化手段。内存 /CPU 优化在我们场景中有很多的优化动作,包括客户端独立进程,Cocos 方向等,下面的环节重点介绍基于 Webview 运行时的内容的优化。

浏览器渲染过程



上面是浏览器渲染相关比较核心的一张图,如果你深入理解了浏览器整个渲染流程,就很清楚浏览器会在哪些阶段会有 CPU 以及内存的消耗,我们可以大概列举如下:


  • JS 代码复杂度及运行频率,会导致 CPU 消耗,操作 DOM 也会消耗内存;

  • JS 代码内存泄漏;

  • DOM 会被解析 LayoutObject,所以复杂大量的 DOM 嵌套,会导致 CPU 和内存的消耗;

  • CSS 同样会被解析 Object,复杂的 CSS 规则会导致 CPU,CSS 规则也可能导致 GPU 内存的消耗;

  • 图片资源,解码 CPU 消耗,渲染是高内存消耗;

  • 回流、重绘会导致 CPU 内存增长;

  • 巧用合成层会减少 GPU 内存消耗,要避免层爆炸。

图片渲染过程


  • IO;

  • 解码(CPU 解码,位图 -> GPU);

  • 渲染管线 (顶点计算 / 光栅化 / 片元着色 / 帧缓冲渲染到屏幕)。

图片内存


  • 位深 (color depth (32 /24 …)。

  • 尺寸 (图片分辨率)。

  • 体积 (磁盘存储所需大小)。


图片占用显存的计算方式如下:


width * height * (colorDepth/8) /(1024 * 1024)= X (M)

1024 * 1024 * (32/8)/(1024 * 1024) = 4M


可以看出图片尺寸对于内存的影响较大。

优化手段


  • 图片压缩 / 图片裁剪;

  • GIF 抽帧,GIF 按照 12fps 抽帧;

  • 动画降帧,Lottie 按照设计帧率运行,并降低至 12fps;

  • 互动题题版,运行时按需加载;

  • GIF 作为合成层渲染,GPU 降低较明显;

  • 信令发送频率及数据量降低;

  • 白板相关优化涉及内容较多,不在这里阐述;

  • Cocos 框架优化,在上一部分内容播放器优化里有介绍。

 总结


  • 黑白屏降至千分位;

  • 追查问题高效;

  • 复杂度降低,迭代成本降低;

  • 单一内容问题,不影响后续播放。


作者介绍:


张士标,作帮直播课堂前端团队负责人,致力于课件、互动系统的持续性能优化和探索。

2022-06-22 11:503465

评论

发布
暂无评论
发现更多内容

什么是Vue3的组合式 API?

源字节1号

软件开发 小程序开发

vue自定义指令

小恺

6月月更

预解析与作用域

Jason199

js 全局作用域 作用域 6月月更

【愚公系列】2022年06月 面向对象设计原则(六)-合成复用原则

愚公搬代码

6月月更

【Python技能树共建】lxml 模块

梦想橡皮擦

Python 6月月更

BottomSheetDialog 使用详解,设置圆角、固定高度、默认全屏等

yechaoa

android dialog 6月月更 material design

数据库每日一题---第9天:销售员

知心宝贝

数据库 算法 前端 后端 6月月更

向线程池提交任务

急需上岸的小谢

6月月更

leetcode 257. Binary Tree Paths 二叉树的所有路径(简单)

okokabcd

LeetCode 搜索 数据结构与算法

一文读懂Logstash原理

恒山其若陋兮

6月月更

统一认证中心 Oauth2 高可用坑

Damon

微服务架构 安全架构 6月月更

WWDC22 开发者需要关注的重点内容

37手游iOS技术运营团队

iOS16 WWDC22 Xcode14 iPadOS16 macOS10.16

LabVIEW控制Arduino实现超声波测距(进阶篇—5)

不脱发的程序猿

单片机 LabVIEW Arduino VISA 超声波测距

LabVIEW Arduino电子称重系统(项目篇—1)

不脱发的程序猿

单片机 LabVIEW VISA ​Arduino Uno 电子称重系统

消息队列入门MQ

卢卡多多

MQ 消息队列 6月月更

volatile的解构

卢卡多多

volatile 6月月更

直播预告|FeatureStore Meetup V3 重磅来袭!

星策开源社区

机器学习 开源 DevOps 特征平台 MLOps

ConcurrentHashMap 源码分析-put方法

zarmnosaj

6月月更

模块八作业

库尔斯

#架构实战营

Flutter doctor 显示xcode没有安装的解决办法

坚果

6月月更

为什么需要微服务

阿泽🧸

微服务 6月月更

【Spring 学习笔记(十)】Spring 使用注解整合 Mybatis

倔强的牛角

Java spring Java EE 6月月更

思科私有动态路由协议:EIGRP

wljslmz

动态路由 6月月更 路由协议 EIGRP

使用 select 切换协程

宇宙之一粟

golang 6月月更

消息队列存储消息数据的 MySQL表

Dean.Zhang

Java—并发容器

武师叔

6月月更

LabVIEW控制Arduino实现红外测距(进阶篇—6)

不脱发的程序猿

单片机 LabVIEW VISA Arduino Uno 红外测距

flutter系列之:flutter中常用的container layout详解

程序那些事

flutter 程序那些事 6月月更

基于华为云图像识别标签实战

乌龟哥哥

6月月更

动态规划之0-1背包问题(详解+分析+原码)

未见花闻

6月月更

RF中使用reuqests的两种方式

红毛丹

Python 6月月更

作业帮直播间前端架构优化实践_大前端_作业帮技术团队_InfoQ精选文章