NGW,前端新技术赛场:Serverless SSR 技术内幕
Category(分类): Other Status: 已读
原文:NGW,前端新技术赛场:Serverless SSR 技术内幕(腾讯云开发者社区,转载自微信公众号"云加社区",作者:IVWEB-ecznlai)。 本文为整理版本,保留原文叙事与技术要点(原文配图为腾讯云资源,此处以文字概括为主)。
一、前言:Serverless + SSR = ?
- Serverless 云函数:云计算发展过程中出现的一种计算资源抽象。以云计算平台为基础为开发者提供业务程序的运行环境,无需关注底层资源分配、扩容部署,代码执行所必要的全部服务由平台提供。
- SSR 服务端渲染:在服务端将 HTML 渲染好再返回前端。早期用 PHP/JSP 在服务端生成 HTML;近年来 JS 同构化趋势下,逐步出现在服务端运行前端 JS 代码渲染的方案(React、Vue 同构渲染)。
将 Serverless 落地到 SSR 场景的优点:
- 云服务资源理论上无限扩容,前端不必考虑业务量对 SSR 机器性能的影响;
- 前端无需关注 SSR 机器的运维、申请、扩容,减少部署运维成本,提高开发效率。
腾讯 NOW 直播 IVWEB 团队当时正逐步将 SSR 业务迁移到腾讯云云函数(SCF)平台上。
二、Serverless 的演进
阿 J 的困境:产品说页面白屏加载慢,阿 J 用团队直出框架半天就把页面接入了直出,但部署到现网时犯了难:
- 部署直出服务要申请机器,申请多少台、几核的?
- 业务量如何、有无高并发场景、机器有没有扩容机制?
- Nginx 配置怎么改才能接入直出?直出失败怎么接入兜底静态页?
从 IaaS 到 FaaS
- 基于虚拟机的业务架构(IaaS):开发者要自己搞定基础层的机器、部署、扩缩容;
- 基于云函数的业务架构(FaaS):开发者无需再关注业务基础层的配置,集中精力处理业务逻辑,基础层由平台负责维护迭代。
FaaS + BaaS 下的 Serverless
FaaS 使服务上云变容易,但FaaS 并没有解决"公共基础服务"的问题——形如对象存储、KV 存储、消息推送这样的基础服务,这个问题最终落到云服务提供商头上,即 BaaS(Backend as a Service)。
Serverless 直译"无服务器",并不是不需要服务器,而是开发者不需要关注服务器——以"函数"承载业务逻辑,以"BaaS 服务"支撑公共服务。
三、SCF 云函数开发
云函数执行过程
Serverless 函数通常用于响应 HTTP 请求:HTTP 访问事件触发云函数执行,平台给出一个 URL,访问即触发。
函数的执行不外乎四个要素:
| 要素 | 内容 |
|---|---|
| 入参 | HTTP 请求中的请求头、请求体 |
| 上下文 | 本次函数请求的 id、执行的环境变量等 |
| 副作用 | 执行中可能调用的外部服务:数据库、对象存储、监控上报 |
| 返回值 | HTTP 响应,如 {retcode:0, msg:"ok"} |
四、NGW Serverless 同构直出方案
阿 J 着手开发时发现,Serverless 环境与原有直出环境有较大出入,五个现实问题:
- 原方案用 TSW 执行 Koa App 直出,需要监听端口而不是作为函数运行,怎么处理?
- 老业务能否无缝迁移?新方案能否兼容老直出方案?
- 云函数怎么工程化打包发布、接入团队现有 CI 流程?
- 原方案可以本地调试,云函数怎么做本地调试?
- 云函数发布后得到一个 URL,怎么接入业务域名?
工程化打包
除前端 webpack 打包外,还要把打包产物"打包为 zip 上传到云函数"。整个部署流程由 CLI 工具承担,提供命令式的部署原语,方便 CI 接入。
Serverless 下的同构环境
不能把整个 TSW 搬进云函数,而是抽取需要的组件(ajax、monitor、logger 等)出来,原因:
- 方便老业务无缝迁移到云函数直出;
- TSW 压缩后近 20 MB、解压后更大,不利于云函数性能(冷启动)。
此外还要自己实现 window.REQUEST plug 这类 TSW 全局注入的对象,旧方案依赖它们。
「流式」和「块式」
云函数的出入参是块式的,Koa 的出入参是流式的。处理方式:根据云函数入参动态构造 Node.js http 的 IncomingMessage 和 ServerResponse 实例,透传给 app.callback() 做直出渲染,最后从 ServerResponse 取出渲染结果,构造为云函数返回值返回。
NGW 作网关转发
为保证业务可用性、解决链路接入的痛苦,接入 NGW(Node Gateway),实现:
- 兜底逻辑:云函数可能 crash,此时走静态页面接入机;
- 灰度逻辑:直出上现网过程中通过 NGW 配置做部分灰度测试;
- 链路日志收归:长期以来前端不好查链路信息,有了 NGW 一切皆有可能。
云函数本地调试
云函数的无状态模型使其非常易于本地调试:只需在本地构造函数的入参、上下文即可直接调试。实现方式:本地起一个 Koa 服务监听端口,用该端口的请求来构造入参、上下文,传入函数执行,结果返回前端显示。
同构直出过程
最终的直出分三步:
- Init:初始化云函数环境,接收并处理入参;
- Koa:React 同构业务逻辑以 Koa App 形式执行(Koa 部分就是原方案的打包结果,做了环境迁移与重写,使其能在云函数环境下渲染);
- Clear:清理云函数环境,处理 Koa Response 返回直出结果。
云函数的性能瓶颈和优化
压测发现:随压力增加收包率断崖式下跌,部分函数执行耗时非常长——冷启动问题。
- 冷启动:云函数触发后不是马上执行,需要环境初始化过程;
- 热启动:函数执行后马上接到下一次请求,无需重新初始化环境,直接启动。
冷启动在低压力下不明显,高并发下严重影响回包。SCF 侧的优化:提高最小实例数——最小实例越多越能扛住瞬时并发,优化后收包率明显恢复。
另一个问题是内存:内存超限导致 4xx,压测压力越大错误越多。经 SCF 侧 Node 内存模型优化后基本消除(业务侧也应优化内存使用、避免 JS 内存泄漏)。
现状和下一步计划
NGW + Serverless SSR 已应用到 NOW 直播、手 Q 附近、浏览器直播和手 Q 群送礼等多个项目,实际业务开发中 Node 业务的部署和运维工作量降低了 80% 以上。
整理者注
本文(约 2019-2020)是腾讯 IVWEB 团队 Serverless SSR 落地的实战记录,与本分类《探索 Serverless 中的前端开发模式》互为印证:
- 前者是"理论与模式"(BFF/SSR 函数化、冷启动原理与优化通则);
- 本文是"工程与内幕"(TSW 组件抽取、流式↔块式转换、NGW 兜底灰度、压测调优)。
文中的"块式入参 → 构造 IncomingMessage/ServerResponse → 复用 Koa App"思路,与后来 Next.js/Nuxt 的 Serverless 适配层(如 vercel/node-bridge)异曲同工;"提高最小实例数抗冷启动"即今天各大 FaaS 平台的"预留实例"功能。文中 TSW(腾讯 Server Worker)已开源并停止积极维护,但其组件化思路仍值得参考。