前端新思路:组件即函数和Serverless SSR实践
Posted Alibaba F2E
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端新思路:组件即函数和Serverless SSR实践相关的知识,希望对你有一定的参考价值。
导读:在今天,对于 Node.js 运维和高并发依然是很有挑战的,为了提效,将架构演进为页面即服务,可是粒度还不够,借着云原生和 Serverless 大潮,无运维,轻松扩展,对前端是极大的诱惑。那么,基于 FaaS 之上,前端有哪些可能性呢?
本次分享主要围绕 Serverless SSR 和它的演进过程、背后思考为主。(长文预警,内含超多干货,请耐心阅读)
文末福利:《2020 前端工程师必读手册》电子书已上线,可免费下载。
2019年上半年,我在阿里经济体前端委员会推进的Serverless研发体系共建项目中负责Serverless SSR的研究,将CSR,SSR,边缘渲染进行整合和尝试,提出组件即服务的概念(Component as Service),试图结合FaaS,做出更简单的开发方式。
本文是狼叔在D2大会的分享《前端新思路:组件即函数和Serverless SSR实践》的内容,阅读需要10分钟,你将了解如下内容:
1.可以了解Serverless时代端侧渲染面临的具体问题
2.可以了解Serverless SSR规范以及渲染体系的完整工作链路和原理
3.为业内提供解决Serverless SSR渲染问题的新思路
今年的技术趋势,我的判断是技术混乱期已过,提效才是今日的挑战。
在Node.js领域,今年新东西也不多,最新已经发布到13,lts是12,Egg.js的生态持续完善,进度也不如前2年,成熟之后创新就少了。在很多框架上加入ts似乎已经政治正确了。比如自身是基于ts的nest框架,比如阿里也开源了基于Egg生态的midway框架,整体加入ts,类型系统和oop,对大规模编程来说是非常好的。另外GraphQL也有很强的应用落地场景,尤其是Apollo项目带来的改变最大,极大的降低了落地成本。已经用rust重写的deno稳步进展中,没有火起来,但也有很高的关注度,它不会替代Node.js,而是基于Node之上更好的尝试。
今日的Node.js存在的问题是会用很容易,做到高可用不容易,毕竟高可用对架构运维要求更好一些,这点对前端同学要求会更难一些。做到高可用之后,做性能调优更难。其实,所有这些难点的背后是基于前端工程师的角度来考虑的,这也是非常现实的问题。
对于很多团队,上Node是找死,不上Node是等死。在今天web框架已经相当成熟,所以如何破局,是当下最破解需要解决的问题。
你可能会感觉Node.js热度不够,但事实很多做Node.js的人已经投身到研发模式升级上了。对于今天的Node.js来说,会用很容易,但用好很难,比如高可用,性能调优,还是非常有挑战的。我们可以假想一下,流量打网关,网关根据流量来实例化容器,加载FaaS运行时环境,然后执行对应函数提供服务。在整个过程中,不许关心服务器和运维工作,不用担心高可用问题,是不是前端可以更加轻松的接入Node.js。这其实就是当前大厂前端在做的前端基于Serverless的实践,比如基于FaaS如何做服务编排、页面渲染、网关等。接入Serverless不是目的,目的是让前端能够借助Serverless创造更多业务价值。
在2017年底,优酷只有passport和土豆的部分页面用Node.js,QPS不高,大多是一些尝试性业务,优酷PC 和H5核心页面还都是php模板渲染。最近2年基于阿里强大的技术体系,我们也对PC、H5多端进行了技术改造。今年双十一是React SSR第一次扛双十一,具有一定意义,背景就不赘述了,参见 。
将优酷C端核心页面全部用Node重写,完成了PHP到Node.js的迁移。在没有PHP同学的情况下,前端可以支撑业务。
性能提升明显,从v1(Bigpipe+jQuery)到v2(React SSR),性能逐步提升。PC页面首屏渲染降到150ms、播放器起播时间从4.6秒优化到2秒。H5站上了React SSR后,性能提升3倍,H5唤端率提升也极其明显,头条短视频唤端率由5.68%提升到9.4%,环比提升65%。单机性能qps从80提升150+(压测最高可以到300左右)。
QPS过万,2年没有p4以上故障,相对来说是比较稳定的。扛过双十一、世界杯,最高三倍以上的流量。
在集团前端委员会承担Serverless SSR专项。
裕波曾经问我,为何如此钟爱SSR?
从前端的角度看,它是一个相对小的领域。PC已经非主流,H5想争王者,却不想被rn、weex中间截胡。怎么看,SSR能做的都有限。但是,用户体验提升是永远的追求,另外web标准化是正统,在二者之间,和Node做结合,除了SSR,目前想不到更好的解法。
贴着C端业务,从后端手里接过来PC、H5,通过Node构建自己的生存之地是必然的选择。
活下来之后就开始有演进,沉淀,通过C端业务和egg-react-ssr开源项目的沉淀,我们成功的打通2点:
写法上的统一:CSR和SSR可以共存,继而实现二种模式的无缝切换
容灾降级方案:从Node SSR无缝切换到Node的CSR,做到第一层降级,从Node CSR还可以继续降到CDN的CSR
2019年,另外一个风口是Serverless,前端把Serverless看成是生死之地,下一代研发模式的前端价值证明。那么,在这个背景下,SSR能做什么呢?基于FaaS的SSR如何呢?继续推演,支持SSR,也可以支持CSR,也就是说基于FaaS的渲染都可以支持的。于是和风驰商量,做了Serverless端侧渲染方向的规划。
本来SSR是Server-side render,演进为Serverless-side render。元彦给了一个非常好概念命名,Caaf,即Component as a fuction。渲染层围绕在以组件为核心,最终统统简化到函数层面。
在今天看,SSR是成功的,一个曾经比较偏冷的点已经慢慢变得主流。集团中,基于React/Rax的一体化开发,可以满足前端所有开发场景。优酷侧的活动搭建已经升级到Rax1.0,对外提供SSR服务。在uc里,已经开始要将egg-react-ssr迁移到FaaS上,代码已经完成迁移。
PC/中后台,React的CSR和SSR
移动端/H5,Rax的CSR和SSR。尤其是Rax SSR给站外H5提供了非常好的首屏渲染时间优化,对C端或活动支持是尤其有用的。
在2020年,基于FaaS之上的渲染已经获得大家的认可。另外大量的Node.js的BFF应用已经到了需要治理的时候,BFF感觉和当年的微服务一样,太多了就会牵扯到管理成本,这种情况下Serverless是个中台内敛的极好解决方案。对前端来说,SSR让开发变得简单,基于FaaS又能很好的收敛和治理BFF应用,结合WebIDE,一种极其轻量级基于Serverless的前端研发时代已经来临了。
从BFF到SFF
了解SSR之前,我们先看一下架构升级,从BFF到SFF的演进过程。
BFF即 Backend For Frontend(服务于前端的后端),也就是服务器设计 API 时会考虑前端的使用,并在服务端直接进行业务逻辑的处理,又称为用户体验适配器。BFF 只是一种逻辑分层,而非一种技术,虽然 BFF 是一个新名词,但它的理念由来已久。
在Node.js世界里,BFF是最合适的应用场景。常见的API、API proxy、渲染、SSR+API聚合,当然也有人用来做网关。
从Backend For Frontend升级Serverless For Frontend,本质上就是利用Serverless基建,完成之前BFF的工作。那么,差异在哪里呢?
核心是从Node到FaaS,本质上还是Serverless,省的其实只是运维和自动扩缩容的工作,一切看起来都是基建的功劳,但对于前端来说,却是极为重大的痛点解决方案,能够满足所有应用场景,基于函数粒度可以简化开发,乃生死必争之地。
SFF 前后端分工
Serverless简单理解是FaaS+BaaS。FaaS是函数即服务,应用层面的对外接口,而BaaS则是后端即服务,更多的是业务系统相关的服务。当下的FaaS还是围绕API相关的工作为主,那么,前端如何和Serverless绑定呢?
Serverless For Frontend(简称SFF)便是这样的概念,基于Serverless架构提供对前端开发提效的方案。
下面看一下SFF分工,这张图我自认为还是非常经典的。首先将Serverless劈成2半,前端和后端,后端的FaaS大家都比较熟悉了,但前端页面和FaaS如何集成还是一片待开发的新领域。
举个例子,常见BFF的例子,hsf调用获得服务端数据,前端通过ctx完成对前端的输出。这时有2种常见应用场景
API,同后端FaaS(RPC居多)
页面渲染(http居多)
基于FaaS的页面渲染对前端来说是必须的。从beidou、Next.js、egg-react-ssr到Umi SSR,可以看出服务端渲染是很重要的端侧渲染组成部分。无论如何,React SSR都是依赖Node.js Web应用的。那么,在Serverless时代,基于函数即服务(Functions as a Service,简写为FaaS)做API开发相关是非常简单的:
1)无服务,不需要管运维工作
2)代码只关系函数粒度,面向API变成,降低构建复杂度
3)可扩展
目前还是Serverless初期,大家还是围绕API来做,那么,在FaaS下,如何做好渲染层呢?直出html,做CSR很明显是太简单了,对于React这种高级玩法如何集成呢?
其实我们可以做的更多,笔者目前能想到的Serverless时代的渲染层具有如下特点。
采用Next.js/egg-react-ssr写法,实现客户端渲染和服务端渲染统一
采用Umi SSR构建,生成独立umi.server.js做法,做到渲染
采用Umi做法,内置Webpack和React,简化开发,只有在构建时区分客户端渲染和服务端渲染,做好和CDN如何搭档,做好优雅降级,保证稳定性
结合FaaS API,做好渲染集成。为了演示Serverless下渲染层实现原理,下面会进行简要说明。在Serverless云函数里,一般会有server.yml作为配置文件,这里以lamda为例子。
SSR 概念升级
现状:
现有FaaS主要是针对API层做扩展,视图渲染是一个新的命题。
竞品Serverless.com提供了Components类似的视图渲染层方案
如何打造一个基于阿里技术栈又有业界领先的端侧渲染解决方案
业界还缺少最佳实践,这是极好的机会。因此,我们对SSR做了概念上的升级(感谢justjavac大佬的提示)
Serverless端渲染层,是针对 SSR
做概念和能力升级:
SSR
从Server side render
升级为Serverless side render
,基于FaaS环境,提供端侧页面渲染能力。Serverless渲染层涵盖的范围扩展,从服务器端渲染升级到同时支持 CSR 和 SSR 2种渲染模式。
在 Serverless 背景下,页面渲染层包含2种情况:
基于 FaaS 的客户端渲染
基于 FaaS 的服务器端渲染
目标是提供基于 FaaS 的页面渲染描述规范,提供标准化组件描述,统一组件写法,用法简单,易实现,可扩展。因此,我们制定了SSR-spec规范,下面会详细讲解。
在讲规范之前,我们先简单了解3个术语:
CSR 和 SSR
先科普一下CSR和SSR的概念。
客户端渲染(简称CSR),简单理解就是html是没有被动态数据灌入的,即所谓的静态页面。比如通过React、Rax编写的组件,打包构建后,以html文件形式分发到CDN上,不需要Node.js支持,就是非常典型的CSR。
资源加载完成后(注意:只有一个bundle,一次性吐出),通过React中的render API进行页面渲染。优点是不需要服务端接入,简单,对于性能要求不高的页面是非常合适的。中后台应用大多是CSR,优化也都是打包环节玩。
服务器端渲染(SSR),简单理解就是html是由服务端写出,可以动态改变页面内容,即所谓的动态页面。早年的php、asp、jsp这些Server page都是SSR的。但基于React技术栈,又有些许不同,server bundle构建的 时候,要吐多少模块,是server端决定的。client bundle和之前一样,差别在于这次是hydrate,而非render。
hydrate是 React 中提供在初次渲染的时候,去复用原本已经存在的 DOM 节点,减少重新生成节点以及删除原本 DOM 节点的开销,来加速初次渲染的功能。主要使用场景是服务端渲染或者像prerender等情况,所以在图中hydrate之后才是tti时间。
如果想全局了解CSR和SSR,共分5个阶段,参考下图。
纯服务端渲染和纯客户端渲染是2个极端,React SSR是属于中间的,这种服务端吐出的粒度是可以根据业务来控制的,可以服务端多一点,性能会差,也可以服务端吐出刚好够首屏的数据,其他由客户端来处理,这种性能会好很多。Static SSR和预渲染的CSR也是特定场景优化的神器。
最佳写法
了解了CSR和SSR的区别,下面我们看一下最佳写法是如何演进的。业内最好的实现大概是next.js了,抛开负责度不谈,单就写法来说,它确实是最合理的。
既然是基于React做法,核心肯定以Component为主,在Component上扩展静态方法用于接口请求是很好的实践。
写法如下:
早年写过bigpipe相关事项,其中模块成为biglet,它的作用是获取接口,结合tpl生成html。
biglet的生命周期如下。
before
.then(self.fetch.bind(self))
.then(self.parse.bind(self))
.then(self.render.bind(self))
end
fetch是获取接口数据,parse解析数据,最终赋值给data。render是模板引擎编译的函数。每个函数的返回值都约定是promise,便于做流程控制。
很明显,biglet和Component是异曲同工的,而fetch是对象上的方法,必须实例化biglet才能调用,而next的做法getInitialProps是静态方法,不必实例化,内存和复用性上都是非常好的。
这点在egg-react-ssr项目技术选型调研期,我们就已经达成一致了。问题是,next只支持SSR,如何能够更好的支持CSR?做到真正的组件级别的同构。于是,基于这种写法,通过高阶组件进行包装,轻松实现了CSR,核心代码如下。
既然写法上统一了,那么,我们还能进一步进行优化么?核心点在网络获取部分。我们能看到的gRPC-web或isomorphic-fetch,分别实现了:1)RPC和http的约定,2)CSR和SSR中fetch统一。给我们带来的启示是在getInitialProps里,我们还可以做更多同构的玩法。
在webpack打包构建server bundle了的时候会注入isBrowser变量。
const plugins = [
new webpack.DefinePlugin({
'__isBrowser__': false //eslint-disable-line
})
]
以此来区分CSR和SSR做同构兼容就更简单了。
Page.getInitialProps = async (ctx) => {
if (__isBrowser__) {
// for CSR
} else {
// for SSR
}
}
以上做法,都是我们基于 https://github.com/ykfe/egg-react-ssr 提炼出来的实践,这些都是SSR-spec的基础。
标FaaS和 SSR 如何结合
有了egg-react-ssr,确立了最佳写法,接下来就是结合FaaS做好集成。
对比一下,getInitialProps的参数和FaaS函数的参数都有context,这个是非常好的:
egg-react-ssr中getInitialProps参数ctx是egg/koa的ctx
FaaS函数的参数context挂了各种函数、内存、日志、client相关的信息,把response信息挂上理论上也是可行的,只是处理位置问题,参见 https://docs.aws.amazon.com/lambda/latest/dg/Nodejs-context.html
解法:给 context 扩展SSRRender方法。
为了演示Serverless下渲染层实现原理,下面会进行简要说明。在Serverless云函数里,一般会有server.yml作为配置文件,这里以lamda为例子。
通过这个配置,我们可以看出函数app.server对应的http请求路径是'/',这个配置其实描述的就是路由信息。对应的app.server函数实现如下图:
通过提供ctx.SSRRender方法,读取dist目录下的Page.server.js完成服务端渲染。
核心要点:
SSRRender方法比较容易实现
采用类似Umi SSR的方式,将源码打包到Page.server.js文件中
在发布的时候,将配置,app.server函数和Page.server.js等文件上传到Serverless运行环境即可
架构升级四阶段
纵观SSR相关技术栈的演进过程,我们大致可以推出架构升级的4阶段:
CSR,很多中后台都是这样的开发的,最常见
其次是阿里开源的beidou,基于egg做的React SSR,这是一个集成度很高的项目,很好用,难度也很大
Umi SSR是基于egg-react-ssr上演进出来的,在umi之上,用户不需要关心webpack,但打包后的代码返回的是stream,这点抽象,云谦做的非常到位,对于开发者来说,还是需要自建Node web server的。
在Serverless里,具体怎么玩是需要我们来创造的。
对照上图,说明如下:
在CSR中,开发者需要关心React和Webpack
在SSR中,开发者需要关心React、Webpack和Egg.js
在Umi SSR同构中,开发者需要关心React和Egg.js,由于Umi内置了Webpack,开发者基本不需要关注Webpack
在Serverless时代,基于FaaS的渲染层,开发者需要关心React,不需要关心Webpack和Egg.js
在这4个阶段中,依次出现了CSR和SSR,之后在同构实践中,对开发者要求更高,甚至是全栈。所有这些经验和最佳实践的积累,沉淀出了更简单的开发方式,在Serverless环境下,可以让前端更加简单、高效。
组件即函数
对于组件写法,我们继续抽象,将布局也拉出来。
function Page(props) {
return <div> {props.name} </div>
}
Page.fetch = async (ctx) => {
return Promise.resolve({
name: 'Serverless side render'
})
}
Page.layout = (props) => {
const { serverData } = props.ctx
const { injectCss, injectScript } = props.ctx.app.config
return (
<html lang='en'>
<head>
<meta charSet='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no' />
<meta name='theme-color' content='#000000' />
<title>React App</title>
{
injectCss && injectCss.map(item => <link rel='stylesheet' href={item} key={item} />)
}
</head>
<body>
<div id='app'>{ commonNode(props) }</div>
{
serverData && <script dangerouslySetInnerHTML={{
__html: `window.__USE_SSR__=true; window.__INITIAL_DATA__ =${serialize(serverData)}`
}} />
}
<div dangerouslySetInnerHTML={{
__html: injectScript && injectScript.join('')
}} />
</body>
</html>
)
}
export default
layout目前看只有第一次渲染有用,但做Component抽象是可以考虑的。现在是首次渲染模式,以后不排除递归组件树的方式(结合bigpipe可以更嗨),那时layout还是有用的。
这样看来,render、fetch、layout是函数,结合Serverless.yml(f.yml)配置,能否将他们放到配置里呢?
路由由f.yml的配置文件中,所以在f.yml增加render配置扩展,具体如下:
functions:
home:
handler: index.handler
render:
- Component: src.home.index
- layout: src.home.layout
- fetch: src.home.fetch
- mode: SSR | CSR(默认SSR)
- injectScript(自己改loyout更好)
- runtime~Page.js
- vendor.chunk.js
- Page.chunk.js
- injectCSS
- Page.chunk.css
- serverBundle: Page.server.js
events:
- http:
path: /
method:
- GET
news:
handler: index.handler
render:
- Component: src.news.index
- layout: src.news.layout
- fetch: src.news.fetch
- mode: SSR | CSR(默认SSR)
events:
- http:
path: /
method:
-
元彦提了一个非常好的命名:组件即函数。最贴切不过。
将渲染、接口请求、布局分别拆成独立函数,放到配置文件里。如此做法,可以保证函数粒度的职责单一,对于可选项默认值也更友好。比如没有接口请求就不调用fetch,或者没有布局使用默认布局。
这里再拔高一下,CSR和SSR写法一致了,这种写法可以和FaaS结合,也就是说写法上拆成函数后,前端关心的只有函数写法了,使得面向组件开发更容易。
我们在抽象一下,提炼3重境界。
组件即函数,就是上面将的内容。
页面即函数,对开发者而言,其实页面的概念不大,第一次渲染布局,然后entry执行而已,如果抛开构建和配置细节,页面就是第一个组件,即函数
页面即服务,是我之前提的概念,每个页面对应一个Node服务,这样的好处是避免服务器雪崩,同时可以降低页面开发复杂度。
对于页面即服务来说,一个FaaS函数提供http,天然就是独立服务,在基建侧,网关根据流量决定该服务的容器个数,完美的解决了页面渲染过程的所有问题,也就是我们只需要关注组件写法,组件写法又都是函数。所以,组 件即函数,是Serverless渲染层最好的概括。
下面这张图很好的表达了组件即函数的核心:统一写法和用法。
制定规范之前,定位还是先要想明白的。
在FaaS rutime之上,保证可移植性
通过CSR和SSR无缝切换,可以保证首屏渲染效率
由于面向组件和配置做到轻量级开发,可以很好的结合
统一写法和用法是件约定大于配置的事儿,约定才是最难的,既要保证功能强大,还要写法简单,又要有扩展性。显然,这是比写代码更有挑战的事儿。
SSR 规范
统一写法,上一小结已经讲过了。
接下来就是规范相关的周边,如下图。
构建,扩展,跨平台,以及目录都需要约定。
SSR-spec(https://github.com/ykfe/ssr#specification)规范主要定义 SSR 特性,组件写法、目录结构以及 f.yml
文件扩展的编写规范。目录结构待讨论,例如新增功能的API与删除功能的API理论上应该放在一个project当中,此时应该在src目录下建立不同的文件夹来隔离不同函数的模块。
├── dist // 构建产物
│ ├── Page.server.js // 服务端页面bundle
│ ├── asset-manifest.json // 打包资源清单
│ ├── index.html // 页面承载模版文件,除非想换成传统的直接扔一个html文件部署的方式
│ └── static // 前端静态资源目录
│ ├── css
│ └── js
├── config // 配置
│ ├── webpack.js // webpack配置文件,使用chainWebpackConfig方式导出,非必选
│ └── other //
├── index.js // 函数入口文件
├── f.yml // FaaS函数规范文件
├── package.json
├── src // 存放前端页面组件
│ ├── detail // 详情页
│ │ ├── fetch.js // 数据预取,非必选
│ │ ├── index.js // React组件,必选
│ │ └── layout.js // 页面布局,非必选,没有默认使用layout/index.js
│ ├── home // 首页
│ │ ├── fetch.js
│ │ ├── index.js
│ │ └── layout.js
│ └── layout
│ └── index.js // 默认的布局文件,必选,脚手架默认生成
└── README.md
命令用法:
$ SSR build
$ SSR deploy
生成的dist目录结构如下:
- dist
- funcName
- static
- clientBundle.js
- js
- css
- images
- serverBundle.js
构建命令:
$ SSR build
$ SSR build --spa
$ SSR build hello
$ SSR build hello2
Serverless集成步骤,通用方案集成:
$ SSR xxx
$ Serverless deploy
这里以Umi为例,开发过程分3个步骤:
本地源码组件开发,然后通过umi dev完成构建
如果是线上,可以走线上构建服务(webpack打包),如果需要修改,可以走
构建后的产物结合FaaS函数,直接发布到Serverless平台上
规范里还有很多点也是有思考的,比如多组件支持是基于bigpipe的方式,首先写入layout布局,然后处理多个组件的组合逻辑,最终res.end即可。另外,组件上如果只有fetch方法,没有render方法也是没有问题的。写法有2种,Component的值是数组,即串行方式。Component的值是对象,即并行方式。限于篇幅,这里就不一一赘述了,参见 https://github.com/ykfe/ssr#specification。
打包与构建
Umi的实现是非常巧妙的,核心在于构建后的server bundle返回值是stream,解耦了对web框架的依赖。在当时还没有实现更好的,所以以Umi为例。
构建产物,各个文件大小的说明,有2种方式:
Node_modules打包到bundle,对FaaS runtime无依赖。
Node_modules不打包到bundle,放到FaaS runtime里。
这2种方式打包大小可以接受,性能上第二种会更好一点,但没有差很多。
标快速切换 CSR 还是 SSR
前面说了写法上的统一,在工程实践中,可以在配置里,直接设置type快速切换CSR还是SSR。在公司内部,还可以通过diamand配置下发的方式进行动态控制。
其实SSR-spec规范里,还做了更多扩展:
//检查query的信息或者url查询参数或者头信息
conf.mode = req.query.SSR || req.headers['x-mode-SSR'];
容灾打底方案
简单地说,有3层容灾:
Node SSR优先,Node调用hsf。
Node CSR通过diamind可以快速切换,html是Node吐出的,前端走MTop请求。
当Node服务挂掉,走CDN上的纯CSR,前端MTop请求。
该流程有以下优点:
构建方式一致
服务端/客户端文件构建方式一致
发布方式一致
发布方式一致,统一发布到 CDN,前端资源可以使用 CDN 加速
无需服务端发布
组件代码变动统一使用 diamond 下发版本号,无需服务端发布
及时生效
diamond 配置下发后可及时生效
如图:
性能优化
性能优化的要点:
控制SSR中server端占的比例,性能和体验是鱼和熊掌不可兼得。看业务诉求。
能缓存的尽量缓存,和BFF应用一样。
这里举个例子,对接口字段瘦身,就可以渠道意想不到的效果。
性能对比
优酷PC的React SSR性能很好,从v1(Bigpipe+jQuery)到v2(React SSR),性能逐步提升。PC页面首屏渲染降到150ms、播放器起播时间从4.6秒优化到2秒。H5站上了React SSR后,性能提升3倍,H5唤端率提升也极其明显,头条短视频唤端率由5.68%提升到9.4%,环比提升65%。单机性能qps从80提升150+(压测最高可以到300左右)。
淘宝的Rax SSR也性能优异,以一个带数据请求的真实 Rax SSR 应用为例,性能对比数据显示:WIFI 下, SSR 的首屏呈现时间相比 CSR 提升 1 倍;弱网环境下,SSR 相比 CSR 提升约 3.5 倍。
未来思考
从用户访问页面流程,具体如下:
要点:
应用网关,肯定是要有的,毕竟要挂域名,反向代理等
页面,已经可以放到FaaS上,FaaS之上的http网关可以满足基本需求,离应用级别的还差很多。
API代理,这个基于Node FaaS函数非常容易实现
API,调用后端服务提供API,比如访问db等,基于Node FaaS函数也是非常容易实现
FaaS细化到函数粒度,在管理上会有巨大挑战,在架构上也需要重新设计:
具有前端特色的函数管理:比如API、Page等类型,path,域名,甚至是具体的应用设置
页面、组件和网关联动,让开发更简单快速
周边,比如监控,统计,数据等等
这里尝试一张图来表示一下前后端的Serverless时代的分工。
统一接入网关是必须的,主要是处理页面和域名的接入。
对于页面进行抽象,围绕组件和搭建来展开,通过在线|本地构建,最终放到页面托管服务中。有了页面托管,才是万里长城的一小步。
接下对API进行拆分,这也是组件组成里重要的部分。
围绕搭建,可以想象到的是组件和接口的抽象。组件除了智能化我能想到的很少,智能化在计算上也能弹性玩就更有想象力了。对于接口可以再细分:
直接操作表,虽不推荐前端做,但确实是必备能力。
通过配置来生成,即元数据管理,对于已有API进行包装,逻辑编排是非常好的。
如果都不满足,自己基于FaaS函数定制就好了。
搭建本身是提效的,组件和接口都能提效,对于前端的价值是尤其大的。前端Serverless专项里,也是有逻辑编排组的,原因大抵如此。
下面再解释一下页面托管服务实现原理。其实这是页面即服务的升级版,以前每个页面对应一个Node服务,这就导致很多Node服务的运维成本非常高,有了Serverless,依然还是一个页面对应一个FaaS函数,但函数的扩容是Serverless基建做的事儿。也就是说页面托管,其实是基于页面的FaaS函数的管理。垂直到页面管理,一切都自动化,会让开发更简单。
最外层,统一接入网关里做应用管理,每个应用都有对应的域名和子应用网关,二者进行绑定 根据流浪,子应用网关也可以自动扩缩容。
在应用设置里,管理子应用网关包含的path和页面,提供反向代理相关的基础功能即可。
设置完子应用包含的页面之后,系统具备将对应页面同步到子应用网关的能力,并且当页面更新的时候能够自动同步,类似于etcd/consul等服务发现同步功能。
有了这部分设计,开发者只需要关注页面的编写就好了。比较上面的3点配置在系统中并不经常做。
基于上面的设计,目的是提高开发速度,沉淀前端中台,具体好处如下:
中后台能够一定程度的收敛到一起,配置化
页面和系统分离,应变能力更强,结合微前端可以有更多想象力
所有开发聚焦到页面维度,能够更好的提效,比如组件沉淀,智能化,搭建等都可以更专注。
很多后端服务也能够很好的沉淀和复用,这和后端常说的能力地图类似,将BFF聚合管理,简化开发
关于未来,我能想到的是:
组件:写代码或智能化生成
页面:配置出来
系统:配置出来
只需要组件级别的函数的轻量级开发模式里,必然会简化前端开发方式,提供人效,最终实现技术赋能业务的目的。在“大中台,小前台”的背景下,贡献前端应变能力。
在《2019,如何放大大前端的业务价值?》一文中,我曾提过:“前端技术趋于成熟,不可否认,这依然是个大前端最好的时代,但对前端来说更重要的是证明自己,不是资源,而是可以创造更多的业务价值。在垂直领域深耕可以让大家有更多生存空间,但我更愿意认为Serverless可以带来前端研发模式上的颠覆,只有简化前后端开发难度,才能更好的放大前端的业务价值。”
致敬所有为Serverless付出的同仁们!
福利来了
重磅下载!
《2020 前端工程师必读手册》
阿里巴巴前端委员会推荐!覆盖语言框架、前端智能化、微前端、Serverless及工程化 5 大热点前端技术方向、10+ 核心实战的前端手册,解锁前端新方式,挖掘前端新思路,尽在此刻,赶紧来先睹为快!
你可能还喜欢 以上是关于前端新思路:组件即函数和Serverless SSR实践的主要内容,如果未能解决你的问题,请参考以下文章