NGW,前端新技术赛场:Serverless SSR 技术内幕

Stella981
• 阅读 705

▎目录:

  1. 前言
  2. Serverless 的演进
  3. 云函数 SCF 的开发
  4. NGW Serverless 同构直出方案

前言

最近 Serverless 又火了,有不少业务上云实装了 Serverless 云函数,取得了不错的落地效果,业界也在不断探索 Serverless 更多的落地场景。

那么对于前端来说,Serverless 意味着什么?对于 Node 服务来说,哪里可以落地 Serverless?

答:Serverless 同构直出渲染。

Serverless + SSR = ?

Serverless 云函数:云计算发展过程中出现的一种计算资源的抽象,它以云计算平台为基础,为开发者提供业务程序的运行环境,开发者无需关注底层资源分配、扩容部署,代码执行所必要的全部服务由平台提供。

SSR 服务端渲染: 指在服务端将 HTML 渲染到前端,早期常用 php jsp 技术来在服务端生成 HTML,近年来 JS 同构化趋势演进下,逐步出现了在服务端上运行前端 JS 代码进行渲染的方案,如 React、Vue 等主流框架的同构渲染。

若能将 Serverless 技术落地到 SSR 场景,将会有如下优点:

  1. 云服务资源理论上无限扩容,前端不必考虑业务量对 SSR 机器性能的影响
  2. 前端同学无需关注 SSR 机器的运维、申请、扩容,减少部署运维成本,提高开发效率

目前腾讯 NOW 直播 IVWEB 团队正逐步将 SSR 业务迁移到腾讯云云函数平台上,精简部署运维成本。

Serverless 的演进

阿 J 是一个前端开发仔,某天产品跟他说页面白屏加载接口的时间太长了,体验差,这对于优秀的前端开发仔的他并不是难事,他有 99 种让页面加载变快的办法。

因此他立马将利用团队直出框架,花了半天时间将页面接入了直出,接下来要将直出服务部署到现网,这时他犯难了:

  1. 部署直出服务需要申请机器,申请多少台,申请几核的?
  2. 这个业务量怎么样,有没有高并发场景,机器有没有扩容机制?
  3. Nginx 配置怎么改才能接入直出,直出失败的话又要怎么接入兜底的静态页面?

一头雾水之时,他看见腾讯云的同事 maxlong 关于 Serverless 架构演进的 PPT….

从 IaaS 到 FaaS

在介绍云函数 SCF 之前,我们先来 diff 一下传统 IaaS 业务架构和云函数 FaaS 业务架构:

NGW,前端新技术赛场:Serverless SSR 技术内幕

而云函数架构是这样的:

NGW,前端新技术赛场:Serverless SSR 技术内幕

阿 J 对比了两者架构之后发现,在基于云函数的业务架构下,开发者无需再关注业务基础层的相关配置,可以集中精力处理业务逻辑的开发,基础层由平台负责维护迭代,只要将我们的直出服务部署上云就可以解决部署直出业务中的运维痛点了。

FaaS + BaaS 下的 Serverless

FaaS 的出现使得服务上云变得容易起来,但是** FaaS 并没有解决「公共基础服务」的问题**,而所谓公共基础服务,就是形如对象存储、KV存储、消息推送这样的基础服务,这个问题最终落到了云服务提供商这里。

因此市面上的云服务无一例外的都提供了上面的「公共基础服务」,这样的服务模式叫做 BaaS(Backend as a Service)。

Serverless 直译过来叫无服务器,这里并不是说不需要服务器,而是说开发者不需要关注服务器,这部分由平台维护提供,开发者仅需关注业务逻辑的开发即可。

NGW,前端新技术赛场:Serverless SSR 技术内幕

在这样的一种架构下,开发者无须关注支撑应用服务运行的底层资源,以「函数」的形式承载业务逻辑,以「BaaS 服务」的形式支撑公共服务。

NGW,前端新技术赛场:Serverless SSR 技术内幕

考虑到直出服务的特性,阿 J 认为直出业务十分适合上 Serverless,因此他立马开始了直出上云的预研,做 Serveless SSR 服务,免去运维部署烦恼,减少直出接入成本!

SCF 云函数开发

阿 J 认真研究了腾讯云云函数(Serverless Cloud Function,SCF),发现它可以将我们的业务拆成更细的粒度「函数」,而函数的执行环境开发者不需要关注,由平台负责,以下是阿 J 对云函数执行的理解。

云函数执行过程

云平台在执行这些「云函数」的过程其实就是在对外提供服务,通常情况下,Serverless 函数会用于「响应 HTTP 请求」,即通过 HTTP 访问事件来触发云函数的执行,如下图所示:

NGW,前端新技术赛场:Serverless SSR 技术内幕

而「函数的执行」不外乎:入参、上下文、返回值、副作用四个要素,如图所示:

NGW,前端新技术赛场:Serverless SSR 技术内幕

四要素:

  1. 「入参」: 云函数的入参即 HTTP 请求中的请求头、请求体
  2. 「上下文」: 包含此次函数请求的 id、函数执行的环境变量等等
  3. 「副作用」: 云函数执行可能调用外部服务,如数据库、对象存储、数据监控
  4. 「返回值」: 即 HTTP 响应如 {retcode:0,msg:"ok"}

阿 J 还了解到根据一定配置部署完云函数之后,云平台会给你一个 URL,通过访问这个 URL 就可以「触发」对应云函数的执行,得到结果。

NGW Serverless 同构直出方案

正当阿 J 着手进行 Serverless 直出开发的时候,他猛然发现,Serverless 环境下跟原有的直出环境有较大出入,原有的直出环境是这样的:

  1. 原方案直出是使用 TSW 执行 Koa App 的方式进行直出的,这意味着原方案需要监听端口而不是作为函数来运行,这个要怎么处理?
  2. 老业务能不能做到无缝迁移到云函数? 能不能做到新直出方案兼容老直出方案?
  3. 云函数怎么做到工程化打包发布,接入到团队现有的 CI 流程中?
  4. 原方案可以做本地调试,而云函数直出怎么做本地调试?
  5. 云函数发布后,会得到一个 URL,那么这个 URL 要怎么接入我们的业务域名下?

工程化打包

除去前端 webpack 打包之外,对于 Serverless 云函数平台,我们还得在原来的打包产物基础上再做一些操作,其核心在于「打包为 zip 上传到云函数」,如下图所示:

NGW,前端新技术赛场:Serverless SSR 技术内幕

从图示中可以看到,打包部署的流程由「CLI 工具」承担,原因是为了提供命令式的部署原语,方便 CI 接入。

Serverless 下的同构环境

阿 J 考虑到原先业务的直出方案采用 TSW 来做,但是在 Serverless 下,我们不能把 TSW 搬进云函数里执行,而是抽取了其中我们需要的组件出来,如 ajax 发送请求、监控上报、日志 logger 等常用组件,因为:

  • 方便老业务无缝迁移到云函数直出,解决直出业务的运维痛点
  • TSW 很大,压缩后近 20 MB,解压出来大很多,不利于云函数的性能

除此之外,还要自己去实现 window.REQUEST plug 类似这样的 TSW 全局注入的对象,因为旧有方案也依赖这些全局对象。

「流式」和「块式」

原来的方案需要 Koa 监听本地端口才能提供服务,而云函数的出入参是块式的,Koa 的出入参是流式的,因此这里需要处理一下云函数的入参。阿 J 的做法是根据云函数入参来动态构造 http 的 IncomingMessage 和 ServerResponse 的实例,然后透传给 app.callback() 进行直出渲染,最后从 ServerResponse 里取得渲染结果构造为云函数返回值返回。

NGW 作网关转发

阿 J 考虑到业务的可用性以及之前链路接入的痛苦,决定接入 NGW(Node Gateway):

NGW,前端新技术赛场:Serverless SSR 技术内幕

通过 NGW 可以做到:

  1. 实现兜底逻辑: 云函数可能会 crash,这时候走静态页面接入机
  2. 灰度逻辑: 直出上现网的过程中可以通过 NGW 的配置进行部分灰度测试
  3. 链路日志收归: 长期以来,前端不好查具体的链路信息,现在有了 NGW 一切皆有可能

云函数本地调试

云函数的无状态模型使得其非常易于进行本地调试,我们只需要在本地构造函数的入参、上下文即可直接进行直出调试了,阿 J 在实际实现中是通过本地起一个 Koa 服务监听端口,利用这个端口的请求来构造入参、上下文,最后传入函数执行结果,返回到前端显示。

同构直出过程

在最后,阿 J 完成了 Serverless 直出方案,其直出过程如下图所示:

NGW,前端新技术赛场:Serverless SSR 技术内幕

  • 「Init」: 初始化云函数环境、接受并处理云函数的入参
  • 「Koa」: React 同构业务逻辑以 Koa App 的形式体现
  • 「Clear」: 清理云函数环境、处理 Koa Response 返回直出结果

特别需要提出的一点是,其中的 Koa 其实就是原方案的打包结果,新方案在此基础上作了一些环境迁移、重写,使其可以在云函数环境下执行渲染。

云函数的性能瓶颈和优化

阿 J 在完成了新直出方案之后马上进行了压测,发现随着压测压力的增加,收包率会出现断崖式下跌,而且还发现部分函数执行耗费时间非常长,联系了云函数的同事看了下发现是「冷启动问题」,那什么是冷启动?

从云函数的架构中可以看到,云函数触发后并不是马上执行,它需要一个环境初始化的过程,这种启动叫做冷启动;还有种情况是,这次请求的函数执行之后马上接到下一次请求,这时候就不用重新初始化云函数环境,而是直接启动,这种称谓热启动。

NGW,前端新技术赛场:Serverless SSR 技术内幕

NGW,前端新技术赛场:Serverless SSR 技术内幕

冷启动问题在压力低的情况下不明显,但是在高并发的情况下就会额外影响回包了,这里SCF 的同事进行了优化:提高最小实例数,减少冷启动,最小实例越多就越能扛住瞬时并发,优化效果如上图右边所示。

此外我们还发现了内存的问题,这里联系了 SCF 的同事进行了 Node 内存模型的相关优化,优化后,已基本不存在 4xx 的问题。

(业务中的内存使用也可以进行优化,要避免 JS 内存泄漏)

NGW,前端新技术赛场:Serverless SSR 技术内幕

NGW,前端新技术赛场:Serverless SSR 技术内幕

到这一步,阿 J 终于初步完成了 Serverless 直出方案设计开发,并开始逐步在业务中使用推广。

现状和下一步计划

NGW,前端新技术赛场:Serverless SSR 技术内幕

目前 NGW + Serverless SSR 已经应用到 NOW 直播、手 Q 附近、浏览器直播和手 Q 群送礼等多个项目中,实际业务开发中,Node 业务的部署和运维工作量降低了 80% 以上。

阿 J 下一步的计划:

  1. 完善的云函数版本管理;
  2. 配合 webpack 进一步优化本地直出调试体验;
  3. 配合腾讯云同事进一步优化云函数性能;
  4. 完善 React Chunked 流式渲染方案,进一步提升首屏加载速度;
  5. 完善 Node 服务云函数,计划做前端 BFF 方案;
  6. 完善直出和链路日志收归,增强服务监控能力。

Serverless Framework 30 天试用计划

我们诚邀您来体验最便捷的 Serverless 开发和部署方式。在试用期内,相关联的产品及服务均提供免费资源和专业的技术支持,帮助您的业务快速、便捷地实现 Serverless!

详情可查阅:Serverless Framework 试用计划

One More Thing

3 秒你能做什么?喝一口水,看一封邮件,还是 —— 部署一个完整的 Serverless 应用?

复制链接至 PC 浏览器访问:https://serverless.cloud.tencent.com/deploy/express

3 秒极速部署,立即体验史上最快的 Serverless HTTP 实战开发!

传送门:

欢迎访问:Serverless 中文网,您可以在 最佳实践 里体验更多关于 Serverless 应用的开发!


推荐阅读:《Serverless 架构:从原理、设计到项目实战》

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这