京东零售技术小哥带你揭秘:亿级流量高并发春晚互动前端技术
一、前言
今年京东再次成为中央广播电视总台春晚独家互动合作平台,这是继 2022 年春晚后的再次携手。本文为你揭开在春晚期间,平台前端团队如何从多个方面进行应对服务器和资损舆情风险双高。
2022 年京东与央视总台春晚双方在红包互动、电商等方面展开全方位深度合作。在除夕当天产生超过 600 亿次互动,送出 15 亿元红包好物。
如何在这种大规模、高并发的场景下,确保系统的稳定性和性能,为用户提供稳定流畅的互动体验,成为了研发小伙伴亟待解决的问题。
接下来我们主要从静态资源优化、服务器资源降本、以及利用工程化提效,来详细介绍前端团队所做的努力和创新。
二、静态资源优化
【首屏资源加载策略】
在春晚主持人口播之后,大量用户会集中在一段时间内涌入互动页面,这会导致流量峰值。为了降低页面打开时的请求次数和资源体积,我们根据页面交互,将所需资源分为三类:首屏、次屏以及操作后。
首屏资源主要包括:HTML 文档、JavaScript、CSS 以及样式图片。由于这是单页面应用,我们可以通过常规技术将 JS 和 CSS 进行打包。对于样式图片,我们可以通过按需加载的方式,显著减小首屏资源体积。
页面包含两个楼层,首屏的互动楼层和次屏的万券齐发楼层。其中,首屏会展示两排优惠券,因此,我们需要在首屏加载这部分券楼层的样式图片。互动主玩法中主要包括抽奖弹窗、邀人弹窗和击鼓游戏。通过拆分优化,首屏的样式图片体积减少约 40%以上。再加上 CDN 降质和 WebP 参数的优化,样式图片的体积可以降低到 178KB。
同时,我们将需要单独加载的击鼓游戏精灵动画图从首屏加载清单中剥离,使得首屏样式图片的加载次数减少一半。这样一来,用户在打开页面时,所需的请求次数和资源体积都得到了显著降低,进而提高了用户体验。
【动画图片低损压缩】
动画是页面资源消耗的主要部分。在春晚页面中,我们需平衡用户交互体验与资源优化。经过与设计和 CDN 团队多次沟通,我们决定采用技术手段降低资源消耗,同时保证用户体验。
首先是确定技术方案。设计团队最初提议使用 3D 模型,需借助 WebGL 进行渲染。但这存在两个问题:一是资源消耗大,3D 模型通常包含 3~4 个文件,首屏加载请求数增加;二是兼容性问题,WebGL 在低端机型上表现不佳。考虑到观众范围广泛,我们决定选用兼容性更好的方案。
经过技术调研,我们最终确定采用帧动画方案:设计团队将 3D 动画转化为精灵图,并将不变部分(如鼓架)单独抽离。精灵图仅包含运动部分(如鼓面敲击动画),有效降低资源消耗。
在确定方案后,设计团队导出了第一版资源文件。然而,精灵图大小为 1236KB,主光效也有 400KB,离我们的目标还有一定差距。经过双方反复尝试,我们通过抽帧方式将击鼓精灵图帧数降至原来的 17%,大小降至原来的 20%。结合降质参数和 WebP 格式,最终大小下降了 90%多。此外,我们将主光效换成放大一倍,并通过 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 优化,使得全站图片大小减小至原来的 58%,经过多种流量和兼容性测试效果表现良好。由此可见,在项目中大量使用图片时,WebP 格式已成为一个不容忽视的性能优化关键。
三、降低服务器成本及风险
春晚活动是一个典型的秒杀业务场景:随着春晚主持人一声令下,全国观众会同一时间涌入活动页面,给接口带来超高的流量压力。下面将从流量削峰、降级处理两个个方面介绍前端如何与后台合作应对这类高并发场景。
【流量削峰】
在高并发场景下,流量削峰有助于系统平稳度过流量高峰。本次活动中,初始化接口和击鼓抽奖接口流量最大,因此我们主要针对这两个接口进行削峰。
1.初始化接口:在页面加载之前,即资源位入口,配置一个“加载中”页面链接。这个页面随机加载 1-3 秒后跳转到活动页面。当流量超过系统承载能力时,开启灰度开关,部分用户进入此页面,然后等待几秒后进入活动页面。
2.击鼓抽奖接口:本次活动的核心玩法接口。如果仅仅是简单地随机延时几秒请求,会极大地影响用户体验。我们采用更精细化的处理方式。已知击鼓交互在用户敲击满次数或倒计时结束时触发抽奖接口,因此,随机设定敲鼓次数,将原本集中在 1-2 秒内的请求打散至 10 秒区间,用户几乎无感知。
【即时状态的本地存储】
针对用户优惠券领取状态的保存问题,权衡了多种因素,如活动规模、服务器端压力和活动持续时长等。最终,我们决定采用前端本地缓存来保存用户领券状态,从而提升性能并优化用户体验。
我们对比了前端常用的本地存储机制,如 cookie、localStorage 和 sessionStorage。然而,这些机制各有优缺点:
1.cookie 存储空间较小,且在与服务端通信时会占用请求头部,可能导致请求头过大,超过服务端设置的最大值,进而引发报错,并增加不必要的网络消耗。
2.sessionStorage 生命周期较短,仅适用于会话期间。
综合考虑后,我们选择了 localStorage 作为优化方案。它具有较长的生命周期和较大的储存空间,能满足业务需求。采用 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 环境和编写稳定高效的发布脚本,降低开发难度,确保每个环境稳定部署。通过这些技术手段和创新,前端团队成功应对了春晚互动项目带来的技术难题,为用户提供了一个稳定流畅的互动体验。
作者:京东零售平台研发 赵越
来源:京东零售技术 转载请注明来源
版权声明: 本文为 InfoQ 作者【京东零售技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/67845cda5d0468afadbd45e31】。文章转载请联系作者。
评论