BBC 发现其网站加载时间每增加一秒,用户便会流失 10%。为提高页面的秒开率,我们不断探索着优化策略,仅仅在浏览器领域下的优化已经满足不了我们的极致要求,开始往服务端方向不断探索。本文将讨论业务接入SSR的几个问题:
SSR究竟适合哪些业务?
接入SSR后,性能带来了哪些提升?
业务接入SSR有哪些成本?
SSR适合哪些业务?
SSR是将页面渲染的过程放在了服务端去执行,对于性能较低的低端机或者网络情况不佳的时候,不需要等待js下载执行就可以直接渲染页面。再加上通常我们会在node层去做首屏接口的聚合,对于用户来说,是可以更快得看到完整渲染的首页,没有抖动的渲染过程,有着更好的用户体验。
总的来说,SSR的优劣势是:
优势
有利于首屏渲染
有利于SEO
对于中低端机型,有较大的性能提升
劣势:
页面白屏时间会较长,渲染完成到真正可交互还需要一段时间
服务端压力较大,会大量占用服务端cpu资源
开发要求高,学习成本相对较高
对于以上的优劣势,再结合本次优化的页面具有以下几个特点,决定采用SSR的渲染方案进行优化:
多渠道投放,分享场景多,引流新用户:业务方会和各种渠道合作,将页面外投来获客。作为需要快速留住用户的落地页,对首屏渲染性能会有着较高的要求。
中低端设备占比高:中低端用户占比 60-70%。低端机主要的性能瓶颈在于代码执行和渲染时间长。
结果对比
左csr,右ssr;浏览器访问,高速3G网络下;
jsTracker SFSP (2022-10-28 00:00:00 —— 2022-11-02 00:00:00) | |||
渲染方式 | 低端机 | 中端机 | 高端机 |
CSR | 1648.02ms | 1543.64ms | 1257.86ms(-211ms) |
SSR | 1545.39ms(-103ms) | 1531.11ms | 1468.47ms |
用户平均数据
TMQ首屏时间 | ||
渲染方式 | 低端机( vivo vivo Y67 ) | 高端机(Realme X50) |
CSR | 2510 ms | 1640ms |
SSR | 1420 ms(-1090ms,-43%) | 880ms(-760ms,-46%) |
单个机型数据
从用户数据对比上来看,低端机性能有所提升,但是高端机反而有降低。这个是符合预期的,因为对于高端机来说,特别是IOS,端侧的性能反而是优于服务器的,SSR的优势反而得不到发挥。但是在天猫优品大促的场景下,用户低端机的平均数据并没有得到很大提升,我们分析有如下几个原因:
我们的页面是一个新页面,目前比较简单,js大小只有97.1 kB,没能体现出SSR请求资源方面的优越性
在CSR和SSR的场景下,我们都使用了首屏的聚合接口。唯一的差别就是渲染方式的差别,在目前手机性能普遍提升的大环境下,就导致数据差异并不大。
so,从这次实践中,可以得出SSR在一些资源较大,较复杂,首屏接口较多的页面,能发挥出更大的优势。
从tmq的单个机型的性能对比中,我们还是可喜的发现数据有不错的提升。so,在之后,我们可以针对某些低性能机型,进行相应的SSR优化。
SSR选型
ICE3.0和RAX的SSR方案对比:
方案 | 工程化 | SSR能力 | 优势 | 劣势 |
Rax | 1、支持一体化,在一个工程中完成页面逻辑和渲染服务的维护,开发、调试、发布更加简单 2、前后端同构,同一份代码既可以进行 CSR 渲染,也可以进行 SSR 渲染 2、低运维成本,无需维护独立 Node 应用,部署即获得 SSR 页面 | 可降级/自动降级/个性化/自定义日志 | 稳定、建设时间较久 | rax体系难以应用到一些最新react社区能力 |
ICE 3.0 | 1、react体系,能力更丰富 2、提供流式渲染能力 | 现有的业务组件都是rax体系,需要兼容和踩坑 |
因为项目对时间和稳定性都有比较高的要求,所以最后我们还是选择了Rax体系。在稳定性的保障上,Serverless 平台提供了基础的灰度、回滚、监控的能力,Rax提供了自动降级能力(当SSR链路出错时,会自动降级到CSR)。
目前,我们上线以来,通过监控观测,SSR的降级率保持在4%以下,服务还是很稳定的。
开发成本
会有很多同学关心,如果将原有的rax应用直接切换到SSR一体化应用中来,成本会有多大?
在SSR的工程中,和CSR工程还是比较类似的,增加了apis目录用于承载渲染函数,还有一些FaaS工程的基本配置。
pages 目录:和普通 CSR 工程一样,承载着页面的渲染逻辑,开发模式和 CSR 应用一样,只需保持代码同时可在 Node 环境下运行即可。
apis 目录:是面向 FaaS 函数的,在 render 目录下,提供了 SSR 渲染函数的入口,其主要工作是调用 Pages 的产物进行渲染。通常,业务开发需要介入的部分是,进行业务数据接口的调用,来准备用于渲染的业务数据。
.
├── build.json
├── f.yml # 函数平台配置
├── jest.config.js
├── midway.config.ts
├── package.json
├── src
│ ├── apis # 函数源码
│ │ ├── configuration.ts
│ │ ├── lambda # 接口
│ │ │ ├── index.test.ts
│ │ │ └── index.ts
│ │ ├── render # 渲染函数
│ │ │ └── index
│ │ │ └── index.ts
│ │ └── typings
│ │ └── context.d.ts
│ ├── app.json
│ ├── app.ts
│ ├── components/
│ ├── document/
│ ├── pages/
│ └── typings.d.ts
└── tsconfig.json
从CSR到SSR的主要工作就是在于聚合首屏接口,改变一下之前获取数据的方式,同时兼容一下SSR和CSR两种渲染方式,保证稳定性。
在前端的工程中,难免会有方法或者库会使用到浏览器环境才有的变量,如 location、navigator等。为保证 SSR 和 CSR 编码的一致性,需要提供在服务器端模拟浏览器环境的能力。
还需注意的是Server 端的渲染过程是一个同步的操作,其本质是将 JSX 组件渲染为 HTML 字符串。因此,setState、hooks 这类异步更新状态的方法以及组件的 生命周期 方法,在 Server 端不会被执行。
在开发过程中,应尽量避免将用于渲染初始页面的数据通过异步的方式来更新。
总结思考
▐ SSR并不是适合所有业务
要结合业务场景和项目状况来综合考虑性能优化的手段,SSR并不是一个万能神方,还是需要对症下药。
▐ 更好的SSR
选择性:结合数据,我们发现中低端机更适合SSR,根据机型来选择不同的渲染方式会更科学,并且也会减少服务器压力。
流式渲染:当服务端计算时间过长或者网络环境不好时,用户会看到比较长的白屏时间;可以通过 ER 先返回一段 HTML 流给用户,让用户可见骨架屏,减少白屏时间。
静态 SSR 、动态更新:在页面没有个性化要求的时候,可以走静态化SSR,将html缓存到cdn上,来达到性能更优的目标。在个性化要求较高的时候,可以使用静态SSR和动态更新的方案,来优化静态链路。
团队介绍
我们是大淘宝技术创新业务前端团队,目前负责消费电子、家装家居、汽车的线上线下零售新模式的探索,面向淘内淘外,提供商家、门店、消费者最佳用户体验。团队沉淀了一定的XR、3D、2D渲染引擎创新体验技术,同时面向全栈领域团队探索了 Serverless 云端研发模式,在消费者前台,通过端智能等手段提升消费者效率,同样面向工程领域,在跨端、前端工程化、中后台微前端都有一些沉淀。如果你是一位充满想象的终端极客,欢迎你的加入,通过自己的技术想法去改变创新业务的终端表达。目前急需校招生小伙伴,简历请投递至: murong.zr@alibaba-inc.com。
¤ 拓展阅读 ¤
3DXR技术 | 终端技术 | 音视频技术
服务端技术 | 技术质量 | 数据算法