听阿里文娱前端技术专家狼叔如重构优酷Node.js,将其性能提升三倍!

在 2017 年底,优酷只有 Passport 和土豆的部分页面用 Node.js,PC 和 H5 核心页面还都是 PHP 模板渲染。而最近 2 年,基于阿里巴巴的技术体系,我们对 PC、H5 多端进行了技术改造。在 2019 年,React SSR 第一次且成功地扛起双 11 重任,具有一定意义。

本文将对这一技术演进之路进行总结和展望,有 2 点突出变化:

1) 我们将优酷 C 端核心页面全部用 Node 重写,完成了 PHP 到 Node.js 的迁移。在没有 PHP 同学的情况下,前端可以支撑业务;

2) 从 Bigpipe+JQuery 到 React SSR,性能明显提升。PC 页面首屏渲染降到 150ms、播放器起播时间从 4.6 秒优化到 2 秒。H5 站上了 React SSR 后,性能提升 3 倍。

一、演进之路

优酷前端团队在之前 PC 首页 / 频道页面改造的基础上,将 React 服务端渲染沉淀出了一个技术框架,该项目已经在 Github 开源,截止 2020 年 1 月底已有 657 star,具体使用方式和源码请查看 egg-react-ssr 项目地址:

https://github.com/ykfe/egg-react-ssr

第一版:Bigpipe + JQuery

 1.  原理:

核心还是采用 Bigpipe + Nunjucks 模板编译实现的。模板 tpl 和 data 编译,生成 html,这个部分其实 Biglet 的 render 方法里做的。然后在请求写入的生命周期上,将 html 分块写入浏览器。

1) 采用 Bigpipe 有 2 大核心优势:

  • 兼容 IE6 等低版本浏览器,不得不用。现代 Web 框架只支持主流浏览器。之前开发对 JQuery 都比较熟悉,二者结合是当时最完美的选择;

  • 业务属性决定的,新老接口拼凑(PHP 的,Java 的,HTTP 的),采用 Bigpipe,利用 Node.js 并发,将接口请求从前端转移到服务端,即可以保证业务快速迭代,也可以保证页面性能。

将页面进一步抽象,以前理解是每个模块都 Biglet。但实际使用中,进行分级处理会更好。

  • 首先渲染布局;

  • 核心:渲染首屏,对于播放页重点是播放器和剧集内容;

  • 其他:看不到的可以偷偷加载,及时不展示也没问题。

2) 性能

 2.  当前:React SSR

采用 React SSR,是在 Node.js Bigpipe 做了一些之后才考虑的。稳定性有了,低版本浏览器兼容有了,接下来就要考虑团队成长和架构升级的问题。

  • 会 JQuery,不会 React,大家是非常想用想学的;

  • Bigpipe 虽好,但依赖模板编译,在内存和 CPU 使用上非常高,优化不易;

  • 老系统慢慢下掉,之前混着新老接口一起用的方式也需要重新梳理。为了快速迭代而产生的“狗粮”还是要吃的。

其实,如果把 React 当模板,结合 Bigpipe,可以达到和之前解决方案一样的效果。问题不能很好的利用 React 的优势,React 自身也提供 SSR 基本能力。所以,我们需要做的是如何结合 React 的 SSR,构建出符合业务特点的 SSR 框架。

 3.  组件级同构: 支持 CSR/SSR 一键切换

在技术调研期,我们分别看了 next.js 和 easywebpack。

  • easywebpack 在使用上,我不认可使用 egg 的 worker 来做。easy-team 的方案本地开发采用了在 Node 中启动 webpack 编译 bundle 的方案,将服务端 bundle 打包在内存中,agent 进程通过 memory-fs 提供的 api 来读取文件内容,并且通过 worker 与 agent 进程的通信, 来让 worker 进程可以获取到文件的字符串内容。然后采用了 Node 的 runInNewContext api, 类似于 eval 的方式去执行 js 字符;

  • next.js 写法上是完美的。结合上面讲过的 Biglet,请求方法抽取成静态方法,可以复用。另外在服务端渲染,先执行请求方法,是最高效的方式;

写法上,最终定了采用 next.js 式的写法。

该技术方案具有以下优点:

  • 实现方式简单优雅

  • SSR/CSR 无缝切换

  • 全面拥抱 JSX

  • 拥抱阿里生态

我们的代码既可以在服务端运行又可以在客户端运行。这里需要重点讲一下 CSR 和 SSR, 我们是业内第一个这样做的。它也带给我们一个意外惊喜,那就是在服务降级上提供了一个更好的方案。

播放页的服务支持两种渲染方式,当服务端有渲染压力时或集群不稳定时,可以切换为客户端渲染,服务端只负责页面的 SEO 数据获取,渲染工作交给浏览器。另外一种方式是当数据源服务出现问题时,可以使用 CDN 数据兜底进行页面容灾。

 4.  组件: 多模块升级配合改造

播放页的页面组件包括首屏、分发区、弹幕、播放器、评论等等一系列的组件,此次播放页升级对应的组件也做了重构,其中弹幕、评论已随新版播放页一起灰度上线。

 5.  服务端 JSBundle 发布: 变更无需发布应用

在 SSR 改造中我们总结出了一套基于配置下发的服务端和客户端文件的流程。该流程有以下优点:

  • 构建方式一致

  • 发布方式一致

  • 服务端 bundle 变化无需走服务端发布

  • 及时生效

下面是发布的流程图:

 6.  性能对比

以预发版本播放页为例,使用 chrome 无痕模式测试。

优酷 PC 播放页:150ms 首屏,首屏文档大小 37kb。文档到达时间平均为 120ms。

优酷 H5 播放页性能提升 3 倍。

二、未来:Serverless SSR

从 beidou、next.js、egg-react-ssr 到 Umi SSR,可以看出服务端渲染是很重要的端侧渲染组成部分。无论如何,React SSR 都是依赖 Node.js Web 应用的。那么,在 Serverless 时代,基于函数即服务(Functions as a Service,简写为 FaaS)做 API 开发相关是非常简单的:

1)无服务, 不需要管运维工作;

2)代码只关系函数粒度,面向 API 变成,降低构建复杂度;

3)可扩展。

在 FaaS 下,如何做好渲染层呢?直出 html,做 CSR 很明显是太简单了,其实我们可以做的更多,Serverless 时代的渲染层具有如下特点:

  • 采用 next.js/egg-react-ssr 写法,实现客户端渲染和服务端渲染统一;

  • 采用 Umi SSR 构建,生成独立 umi.server.js 做法,做到渲染;

  • 采用 Umi 做法,内置 webpack 和 React,简化开发,只有在构建时区分客户端渲染和服务端渲染,做好和 CDN 配合,做好优雅降级,保证稳定性;

  • 结合 FaaS API,做好渲染集成。

通过提供 ctx.ssrRender 方法,读取 dist 目录下的 Page.server.js 完成服务端渲染。核心要点:

  • ssrRender 方法比较容易实现;

  • 采用类似 Umi SSR 的方式,将源码打包到 Page.server.js 文件中;

  • 在发布的时候,将配置,app.server 函数和 Page.server.js 等文件上传到 Serverless 运行环境即可。

综上所述,我们大致可以推出架构升级的 4 个阶段。

  • 在 CSR 中,开发者需要关心 React 和 webpack;

  • 在 SSR 中,开发者需要关心 React、webpack 和 egg.js;

  • 在 Umi SSR 同构中,开发者需要关心 React 和 egg.js,由于 Umi 内置了 webpack,开发者基本不需要关注 webpack;

  • 在未来,基于 FaaS 的渲染层,开发者需要关心 React,不需要关心 webpack 和 egg.js。

在这 4 个阶段中,依次出现了 CSR 和 SSR,之后在同构实践中,对开发者要求更高,甚至是全栈。所有这些经验和最佳实践的积累,沉淀出了更简单的开发方式,在未来 Serverless 环境下,希望前端更加简单、高效。

 1.  规范

上图的最小示例代码中描述了一个页面如何进行数据获取和展示,其中 render(必选)、getInitialProps(可选) 均为方法,在 SSR 模式下页面数据传输模式可以为简单模式和 Bigpipe 模式。

 2.  实现

实现上基于 FaaS 规范,使用 React 同构写法,构建后的目录结构如上图,最终通过调用 ssrRender 方法进行服务端渲染,将页面 HTML 返回客户端。

 3.  生态

目前集团沉淀的前端生态已经被开发者大量使用,从 React 的组件库、框架、多端方案, 到 Node.js 的 WEB 框架,相信在未来的 Serverless 环境下,会有更多优秀的方案或框架加入到集团生态,使前端开发更加的快捷、高效。

三、致敬所有多端坚守者

感谢苹果,将用户体验提升到了前无古人的位置。移动互联网兴起后,PC Web 日渐没落。在 AI 时代,没有“端”的支持可以么?明显是不可以的。不只是“端”的概念,而是真真正的用户体验。

1)  我们可以利用 PC/H5 快速发版本的优势,快速验证 AI 算法,继而为移动端提供更好的模型和数据上的支撑;

2)  多端对齐,打好组合拳。既然不能在移动端有更大的突破,大家只能在细节上血拼。按照木桶原理,哪个地方是短板,整体水位就在那里。

今天的大前端,除了 Web 外,还包括各种端,比如移动端、OTT,甚至是新的物联网设备。我们有理由相信 Chrome OS 当年的远见:“给我一个浏览器,我就能给你一个世界”。

 活动推荐

随着大前端的发展,Node.js 也已经发布到 v13,其应用场景从脚手架、辅助前端开发(比如 SSR、PWA 等)的快速开发实践,到 API 中间层、代理层,甚至到后端开发都有非常成熟的经验。

发布了837 篇原创文章 · 获赞 752 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/qq_41946557/article/details/105018024