前言

2022年1月,京东成为央视总台2022年春节联欢晚会独家互动合作伙伴,双方在红包互动、电商等方面展开全方位深度合作。在除夕当天产生691亿次互动,送出15亿元红包好物。

如何在这种大规模、高并发的场景下,确保系统的稳定性和性能,为用户提供稳定流畅的互动体验,成为了我们亟待解决的问题。

接下来我们主要从静态资源优化、缓存、容错、工程化几个方面来详细介绍前端团队所做的努力和创新。

静态资源优化

首屏资源加载策略

在春晚主持人口播之后,大量用户会集中在一段时间内涌入互动页面,这会导致流量峰值。为了降低页面打开时的请求次数和资源体积,我们根据页面交互,将所需资源分为三类:首屏、次屏以及操作后。

首屏资源主要包括:HTML文档、JavaScript、CSS以及样式图片。由于这是单页面应用,我们可以通过常规技术将JS和CSS进行打包。对于样式图片,我们可以通过按需加载的方式,显著减小首屏资源体积。

页面包含两个楼层,首屏的互动楼层和次屏的万券齐发楼层。其中,首屏会展示两排优惠券,因此,我们需要在首屏加载这部分券楼层的样式图片。互动主玩法中主要包括抽奖弹窗、邀人弹窗和击鼓游戏。通过拆分优化,首屏的样式图片体积减少约41%。再加上CDN降质和WebP参数的优化,样式图片的体积可以降低到178KB。

同时,我们将需要单独加载的击鼓游戏精灵动画图从首屏加载清单中剥离,使得首屏样式图片的加载次数从2次减少到1次。这样一来,用户在打开页面时,所需的请求次数和资源体积都得到了显著降低,进而提高了用户体验。

 

动画图片低损压缩

动画是页面资源消耗的主要部分。在春晚页面中,我们需平衡用户交互体验与资源优化。经过与设计和CDN团队多次沟通,我们决定采用技术手段降低资源消耗,同时保证用户体验。

首先是确定技术方案。设计团队最初提议使用3D模型,需借助WebGL进行渲染。但这存在两个问题:一是资源消耗大,3D模型通常包含3~4个文件,首屏加载请求数增加;二是兼容性问题,WebGL在低端机型上表现不佳。考虑到观众范围广泛,我们决定选用兼容性更好的方案。

经过技术调研,我们最终确定采用帧动画方案:设计团队将3D动画转化为精灵图,并将不变部分(如鼓架)单独抽离。精灵图仅包含运动部分(如鼓面敲击动画),有效降低资源消耗。

 

 

 

 

在确定方案后,设计团队导出了第一版资源文件。然而,精灵图大小为1236KB,主光效也有400KB,离我们的目标还有一定差距。经过双方反复尝试,我们通过抽帧方式将击鼓精灵图从24帧降至4帧,大小从1236KB降至265KB。结合降质参数和WebP格式,最终大小仅为78KB,下降了93%。此外,我们将主光效换成放大一倍的一倍图,并通过CSS属性scale实现放大,进一步节省资源。

 

雪碧图方案的演进

元素背景图使用雪碧图模式,是前端基本优化手段,可以显著降低请求次数。我们在首屏资源拆分后的情况下,可以将18个样式背景图合并成1个。相较于常规方案,春晚红包还扩展了2个功能:

1、css雪碧图在运行时为图片URL添加CDN降质参数和webp格式转换参数(someimage.png!q70.webp),极限降低CDN带宽。我们扩展开发了自动雪碧图脚本,可以支持自动生成2套background-image样式代码,分别对应普通图片URL和带!q70.webp的URL。通过运行时检测webp支持特性,切换HTML标签上的class名,来使对应的后代选择器的background-image属性生效。对于webp的特性检测的技术方案,我们考虑过如下两种方案:

a、通过版本判断,从caniuse看,可以按照只有iOS14以下不支持webp来作为判断依据。

 

 

 

 

b、通过创建一个Image对象,其src为一个基于base64的webp图片,根据load是否成功来判断是否支持webp。

比较这2个方案,方案a的优势是通过UA判断系统版本是同步执行的,可以在调用渲染页面前的任意地方执行并修改HTML标签的class属性。确保内容渲染后有正确的背景图css生效。不会对原有渲染逻辑产生入侵性修改。而方案b的优势是经过大规模实践,判断逻辑的可靠性较高,缺点是异步逻辑的,需要修改原来的渲染逻辑。由于我们这次需要支持全国亿万用户,为确保稳定可靠,所以最终选择方案b。

css文件中的背景图样式,是在渲染相应DOM的时候才发起请求,又由于React渲染是同步的,我们需要调整执行render的时机,以确保在渲染页面内容之前完成HTML的class属性设置,避免请求两次图片。

 

 

 

 

 

2、动态雪碧图。万券齐发楼层首屏露出2排8个坑位,对应8次logo图片请求,由于券和logo的数据是通过接口下发的,所以无法使用编译时雪碧图方案。为了将图片请求次数减少到1次,我们和后台、视觉、产品沟通后,设计了一套多团队协作的方案。设计同学可以根据产品提前确认的券位置将logo图合并成雪碧图,并上传到云存储。展示如下:

 

 

 

雪碧图规格确定后,通过固定的background-position属性,以及动态设置logo元素的className和背景图,即可实现动态雪碧图。

 

 

 

自动衍生WebP背景图css代码

上面提到运行时判断是否使用webp背景图,那对应的css代码就需要两套,利用PostCSS插件可以在编译时自动基于原有背景图样式代码生成webp背景图的代码,在紧张的开发过程中避免出错和遗漏。通过使用PostCSS插件中,CSS对象的walkDecls方法,我们可以遍历所有的background-image属性。然后,使用正则表达式匹配对应的样式,在编译打包时生成一套.webp .origin-class选择器的样式。在运行时,如果HTML标签具有webp属性,系统将后代选择器的样式覆盖原有样式。

 

 

 

 

除了img标签,我们在背景图也进行了webp优化,使得全站图片由902.4kb减小到512.6kb,经过多种流量和兼容性测试效果表现良好。由此可见,在项目中大量使用图片时,WebP格式已成为一个不容忽视的性能优化关键。

降低服务器成本及风险

春晚活动是一个典型的秒杀业务场景:随着春晚主持人一声令下,全国观众会同一时间涌入活动页面,给接口带来超高的流量压力。下面将从流量削峰、降级处理两个个方面介绍前端如何与后台合作应对这类高并发场景。

流量削峰

在高并发场景下,流量削峰有助于系统平稳度过流量高峰。本次活动中,初始化接口和击鼓抽奖接口流量最大,因此我们主要针对这两个接口进行削峰。

1.初始化接口:在页面加载之前,即资源位入口,配置一个“加载中”页面链接。这个页面随机加载1-3秒后跳转到活动页面。当流量超过系统承载能力时,开启灰度开关,部分用户进入此页面,然后等待几秒后进入活动页面。

2.击鼓抽奖接口:本次活动的核心玩法接口。如果仅仅是简单地随机延时几秒请求,会极大地影响用户体验。我们采用更精细化的处理方式。已知击鼓交互在用户敲击满次数或倒计时结束时触发抽奖接口,因此,随机设定敲鼓次数,将原本集中在1-2秒内的请求打散至10秒区间,用户几乎无感知。

即时状态的本地存储

针对用户优惠券领取状态的保存问题,权衡了多种因素,如活动规模、服务器端压力和活动持续时长等。最终,我们决定采用前端本地缓存来保存用户领券状态,从而提升性能并优化用户体验。

我们对比了前端常用的本地存储机制,如cookielocalStoragesessionStorage。然而,这些机制各有优缺点:

1.
cookie存储空间较小(4K),且在与服务端通信时会占用请求头部,可能导致请求头过大,超过服务端设置的最大值,进而引发报错,并增加不必要的网络消耗。 2.
sessionStorage生命周期较短,仅适用于会话期间。

综合考虑后,我们选择了localStorage作为优化方案。它具有较长的生命周期和较大的储存空间(2.5M-4M),能满足业务需求。采用localStorage缓存数据,不仅可以简化调用链路、降低风险和节约成本,还能直接从本地读取券的领取状态,避免网络延迟导致的响应时间过长,提升用户体验。

工程化

为了使业务开发人员能更专注于自身业务开发,我们将手机兼容性、设备分级、环境判断、自动合成雪碧图、自动图片压缩、自动上传云存储、合并代码文件等通用解决方案统一纳入工程化层面处理。

通过工程化,可以最大程度的释放生产力和创造力。上述的各种前端各种优化方案,离不开工程化的助力,与此同时保证了在快速开发交付的效率和稳定性。

提供拟真的MOCK环境

我们搭建了一个拟真的MOCK环境,以在短时间内模拟所需场景,确保在任意场景下都能提供友好交互。该环境1:1还原了服务端的MOCK环境,能快速模拟正常数据,同时还能模拟请求超时、HTTP状态码异常、数据结构异常、非常规业务异常码等场景。在ajax模块中,我们采用透明转发方式,降低业务开发同学创作mock数据的成本,避免mock数据进入生产环境。如图所示,MOCK开发环境与联调开发环境对比,可以看出mock环境对业务开发来说是透明且无副作用的,同时又能快速MOCK数据。

 

 

 

编写稳定高效的发布脚本

春晚参与用户的设备种类繁多,我们需在不同设备上实现极致体验,同时减轻CDN过高QPS的压力。为此,我们与客户端团队联合,根据不同设备的不同版本,提供了内置包、离线包和线上CDN包等多套环境。结合多轮内测和公测,在短短27天内,需部署10多套环境。线上环境部署错综复杂,还包括资源收集和大小计算等工作。若采用人工方式,极易出现误操作,带来不良后果。幸运的是,项目初期便引入了环境变量,通过环境变量解决不同环境间的差异。此外,在编译前后加入了一系列脚本,替代人工拷贝上传、资源收集、大小计算等操作,避免人工操作失误,提高稳定性,确保每个环境稳定部署。

 

 

 

 

工程化的目标,始终是提升开发效率,降低开发难度,分离关注点,让业务研发同学更专注于自身业务的开发。

容灾

作为一档全球直播节目,现场不免会出现各种状况,需要做好各种紧急预案。降级处理分为主动降级和被动降级两类:

1.主动降级:各个资源位和交互按钮上添加降级开关,上游接口或下游页面出现紧急情况时,可通过配置CMS快速打开降级开关。

2.被动降级:通过不同样式和文案提示区分各类接口异常码及系统环境,快速定位问题原因。这样一来,客服同学可以第一时间安抚客户,并提供相应处理方案。

总结

2022年央视春晚互动项目是一次大规模、高并发的挑战,前端团队通过静态资源优化、缓存、容错和工程化等方面的努力和创新,确保了系统的稳定性和性能,为用户提供了一个稳定流畅的互动体验。在静态资源优化方面,团队通过首屏资源拆分、帧动画方案替代3D模型、动态雪碧图和WebP格式优化等技术手段,显著降低了资源消耗和请求次数。在降低服务器成本及风险方面,选择localStorage作为非常规优化方案,提升用户体验。在容错方面,流量削峰和降级处理,确保系统稳定运行。在工程化方面,统一处理通用解决方案、提供拟真的MOCK环境和编写稳定高效的发布脚本,降低开发难度,确保每个环境稳定部署。通过这些技术手段和创新,前端团队成功应对了春晚互动项目带来的技术难题,为用户提供了一个稳定流畅的互动体验。

 

作者:京东零售 赵越

来源:京东云开发者社区 转载请注明来源