如何将 Web 框架迁移到 Serverless
Serverless 通常翻译为「无服务架构」,是一种软件系统设计架构思想和方法,并不是一个开发框架或者工具。他的出现是为了让开发者更加关注业务的开发,而将繁杂的运维和部署交给云厂商。Serverless 由 Faas 和 Baas 组成,Faas 为开发者提供业务运算环境,然后与 Baas 提供的数据和存储服务,进行交互,从而提供与传统服务一致的体验。但是由于 Faas 是无状态的,并且其运行环境是有读写限制的,最重要的是它是基于事件触发的。因此如果传统 Web 服务想迁移到 Serverless 上,是需要进行相关改造和特殊处理的,为此迁移成本是必不可少的。本文将具体帮助大家剖析下,如何 Serverless 化传统的 Web 服务。
读完本文将了解到:
传统 Web 服务特点
Web 服务定义:
Web 服务是一种
面向服务的架构
(SOA) 的技术,通过标准的 Web 协议提供服务,目的是保证不同平台的应用服务可以互操作。
日常生活中,接触最多的就是基于 HTTP 协议的服务,客户端发起请求,服务端接受请求,进行计算处理,然后返回响应,简单示意图如下:
传统 Web 服务部署流程:通常需要将项目代码部署到服务器上,启动服务进程,监听服务器的相关端口,然后等待客户端请求,从而响应返回处理结果。而这个服务进程是常驻的,就算没有客户端请求,也会占用相应服务器资源。
一般我们的服务是由高流量和低流量场景交替组成的,但是为了考虑高流量场景,我们需要提供较高的服务器配置和多台服务进行负载均衡。这就导致服务处在低流量场景时,会多出很多额外的闲置资源,但是购买的资源却需要按照高流量场景进行付费,这是非常不划算的。
如果我们的服务能在高流量场景自动扩容,低流量场景自动缩容,并且只在进行计算处理响应时,才进行收费,而空闲时间不占用任何资源,就不需要收费呢?
答案就是 Serverless
。
Serverless 适用场景
上面已经提到了 Serverless 的两个核心特点:按需使用和收费
和 自动扩缩容
。而且近几年 Serverless 的应用也越来越广泛,但是它并不是银弹,任何技术都是有它的适合场景和不适合场景。我们不能因为一项技术的火热,而盲目的追捧。Serverless 是有它的局限性的,一般 Serverless 适合如下几种场景:
- 异步的并发,组件可独立部署和扩展
- 应对突发或服务使用量不可预测
- 无状态,计算耗时较短服务
- 请求延时不敏感服务
- 需要快速开发迭代的业务
如果你的服务不满足以上条件,笔者是不推荐迁移到 Serverless。
Web 框架如何迁移到 Serverless
如果你的服务是以上提到的任何话一个场景,那么就可以尝试迁移到 Serverless 上。
常见的 Serverless HTTP 服务结构图如下:
那么我们如何将 Web 服务进行迁移呢?
我们知道 Faas (云函数)是基于事件触发的,也就是云函数被触发运行时,接收到的是一个 JSON 结构体
,它跟传统 Web 请求时有区别的,这就是为什么需要额外的改造工作。而改造的工作就是围绕如何将事件 JSON 结构体转化成标准的 Web 请求
。
所以 Serverless 化 Web 服务的核心就是需要开发一个 适配层
,来帮我们将触发事件转化为标准的 Web 请求。
整个处理流程图如下:
接下来将介绍如何为 Express 框架开发一个适配层。
Serverless Express 适配层开发
实现原理
首先我们先来看看一个标准的云函数结构:
module.exports.handler = (event, context) => { // do some culculation return res; };
在介绍如何开发一个 Express 的适配层前,我们先来熟悉下 Express 框架。
一个简单的 Node.js Web 服务如下:
const http = require("http"); const server = http.createServer(function (req, res) { res.end("helloword"); }); server.listen(3000);
Express 就是基于 Node.js 的 Web 框架,而 Express 核心就是 通过中间件的方式,生成一个回调函数
,然后提供给 http.createServer()
方法使用。
Express 核心架构图如下:
由此可知,我们可以将 Express 框架生成的回调函数,作为 http.createServer()
的参数,来创建可控的 HTTP Server,然后将云函数的 event
对象转化成一个 request
对象,通过 http.request()
方法发起 HTTP 请求,获取请求响应,返回给用户,就可以实现我们想要的结果。
Node.js Server 的监听方式选择
对于 Node.js 的 HTTP Server,可以通过调用 server.listen()
方法来启动服务,listen()
方法支持多种参数类型,主要有两种监听方式 从一个TCP端口启动监听
和 从一个UNIX Socket套接字启动监听
。
server.listen(port[, hostname][, backlog][, callback])
:从一个TCP端口启动监听server.listen(path, [callback])
:从一个UNIX Domain Socket启动监听
服务器创建后,我们可以像下面这样启动服务器:
// 从'127.0.0.1'和3000端口开始接收连接 server.listen(3000, '127.0.0.1', () => {}); // 从 UNIX 套接字所在路径 path 上监听连接 server.listen('path/to/socket', () => {})
无论是 TCP Socket
还是 Unix Domain Socket
,每个 Socket 都是唯一的。TCP Socket
通过 IP和端口
描述,而 Unix Domain Socket
通过 文件路径
描述。
TCP 属于传输层的协议,使用 TCP Socket 进行通讯时,需要经过传输层 TCP/IP 协议的解析。
而 Unix Domain Socket
可用于不同进程间的通讯和传递,使用 Unix Domain Socket
进行通讯时不需要经过传输层,也不需要使用 TCP/IP 协议
。所以,理论上讲 Unix Domain Socket
具有更好的传输效率。
因此这里在设计启动服务时,采用了 Unix Domain Socket
方式,以便减少函数执行时间,节约成本。
关于 Node.js 如何实现 IPC 通信,这里就不详细介绍的,感兴趣的小伙伴可以深入研究下,这里有个简单的示例,nodejs-ipc
代码实现
原理大概介绍清楚了,我们的核心实现代码需要以下三步:
- 通过 Node.js HTTP Server 监听 Unix Domain Socket,启动服务
function createServer(requestListener, serverListenCallback) { const server = http.createServer(requestListener); server._socketPathSuffix = getRandomString(); server.on("listening", () => { server._isListening = true; if (serverListenCallback) serverListenCallback(); }); server .on("close", () => { server._isListening = false; }) .on("error", (error) => { // ... }); server.listen(`/tmp/server-${server._socketPathSuffix}.sock`) return server; }
- 将 Serverless Event 对象转化为 Http 请求
function forwardRequestToNodeServer(server, event, context, resolver) { try { const requestOptions = mapApiGatewayEventToHttpRequest( event, context, getSocketPath(server._socketPathSuffix), ); // make http request to node server const req = http.request(requestOptions, (response) => forwardResponseToApiGateway(server, response, resolver), ); if (event.body) { const body = getEventBody(event); req.write(body); } req .on('error', (error) => // ... ) .end(); } catch (error) { // ... return server; } }
- 将 HTTP 响应转化为 API 网关标准数据结构
function forwardResponseToApiGateway(server, response, resolver) { response .on("data", (chunk) => buf.push(chunk)) .on("end", () => { // ... resolver.succeed({ statusCode, body, headers, isBase64Encoded, }); }); }
最后函数的 handler 将异步请求返回就可以了。
借助 tencent-serverless-http 库实现
如果不想手写这些适配层代码,可以直接使用 tencent-serverless-http 模块。
它使用起来很简单,创建我们的 Express 应用入口文件 sls.js
:
const express = require("express"); const app = express(); // Routes app.get(`/`, (req, res) => { res.send({ msg: `Hello Express`, }); }); module.exports = app;
然后创建云函数 sl_handler.js
文件:
const { createServer, proxy } = require("tencent-serverless-http"); const app = require("./app"); exports.handler = async (event, context) => { const server = createServer(app); const result = await proxy(server, event, context, "PROMISE").promise; };
接下来,将业务代码和依赖模块一起打包部署到云函数就可以了(记得指定 执行方法
为 sl_handler.handler
)。
其他 Node.js 框架
除了 Express
框架,其他的 Node.js 框架也基本类似,只需要按照要求,exports
一个 HTTP Server
的回调函数就可以。
比如 Koa
,我们拿到初始化的 Koa
应用后,只需要将 app.callback()
作为 createServer()
方法的参数就可以了,如下:
const { createServer, proxy } = require("tencent-serverless-http"); const app = require("./app"); exports.handler = async (event, context) => { // 这里和 Express 略有区别 const server = createServer(app.callback()); const result = await proxy(server, event, context, "PROMISE").promise; };
其他语言框架
对于非 Node.js 框架,比如 Python
的 Flask
框架,原理都是一样的,核心只需要做到 将 Serverless Event 对象转化为 Http 请求
,就可以了。由于笔者对其他语言不太熟悉,这里就不做深入介绍了,感兴趣的小伙伴,可以到 Github 社区搜索下,已经有很多对应的解决方案了,或者自己尝试手撸也是可以的。
使用 Serverless Components 快速部署 Web 框架
读到这里,相信你已经清楚,如何将自己的 Node.js 框架迁移到 Serverless 了。但是在这之前,我们都是手动处理的,而且每次都需要自己创建 handler.js
文件,还是不够方便。
为此开源社区提供了一套优秀的解决方案 Serverless Component,通过组件,我们进行简单的 yaml
文件配置后,就可以方便的将我们的框架代码部署到云端。
比如上面提到的 Express
框架,就有对应的组件,我们只需要在项目根目录下创建 serverless.yml
配置文件:
component: express name: expressDemo inputs: src: ./ region: ap-guangzhou runtime: Nodejs10.15 apigatewayConf: protocols: - https environment: release
然后全局安装 serverless
命令 npm install serverless -g
之后,执行部署命令即可:
$ serverless deploy
耐心等待几秒,我们的 Express 应用就成功部署到云端了。更多详细信息,请参考 Express 官方文档
注意:本文 Serverless 服务均基于
腾讯云
部署。
Serverless Express 组件不仅能帮我们快速部署 Express 应用,而且它还提供了 实时日志
和 云端调试
的能力。
只需要在项目目录下执行 serverless dev
命令,serverless 命令行工具就会自动监听项目业务代码的更改,并且实时部署,同时我们可以通过打开 Chrome Devtools 来调试 Express 应用。
关于云端调试,腾讯云 Serverless Framework 正式发布公告 中有详细的介绍,并且有视频演示。
而且除了 Express 组件,还支持: Koa.js,Egg.js,Next.js,Nuxt.js.....
最后
当然 Serverless 化 Web 服务并没有本文介绍的那么简单,比如文件读写,服务日志存储,Cookie/Session
存储等......实际开发中,我们还会面临各种未知的坑,但是比起困难,Serverless 带给我们的收益是值得去尝试的。当然传统 Web 服务真的适合迁移到 Serverless 架构上,也是值得我们去思考的问题,毕竟现有的 Web 框架都是面向传统 Web 服务开发实现的 (推荐阅读 利与弊-传统框架要不要部署在 Serverless 架构上)。但是笔者相信,很快就会出现一个专门为 Serverless 而生的 Web 框架,可以帮助我们更好地基于 Serverless 开发应用 ~
One More Thing
3 秒你能做什么?喝一口水,看一封邮件,还是 —— 部署一个完整的 Serverless 应用?
复制链接至 PC 浏览器访问:https://serverless.cloud.tencent.com/deploy/express
3 秒极速部署,立即体验史上最快的 Serverless HTTP 实战开发!
传送门:
- GitHub: github.com/serverless
- 官网:serverless.com
欢迎访问:Serverless 中文网,您可以在 最佳实践 里体验更多关于 Serverless 应用的开发!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
从 GPU、TPU,到 Web 端、移动端,深度学习框架部署训练开始变简单
早些时候的统计显示,今年3月,深度学习框架集中爆发。5月,有人发布可以直接在 iphone11上训练神经网络的开源项目。日前,百度开源国内首个可直接运行在 Web 端的深度学习框架 Paddle.js。这些都使深度学习框架的部署和训练变得简单。 深度学习框架提供一系列的深度学习组件,开发者选择一套框架之后,可以自定义数据集、算法、参数等,通过训练得到模型参数。就像一套供自由拼装的积木,玩家可直接搭建模型,而不用先去做木工,造方块。 3月开源的华为全场景 AI 计算框架 MindSpore;旷视深度学习框架天元 MegEngine;清华大学发布基于元算子和动态编译的深度学习框架计图 Jittor,就提供了国产 AI 训练的“积木”。 深度学习框架训练模型通常要求设备具有强大的算力,因此过去多是在 GPU 或是 TPU 上训练,之后再压缩部署到各终端设备。上述的三个框架也不例外。一些较为常见的、可以部署在 Web 端的框架也都尚未支持端训练。比如东京大学机器智能实验室的 WenDNN,只支持任务的推断阶段,不能用在训练阶段。Keras.js 只支持 Keras 生成的模型,不支持模型训练,...
- 下一篇
DRS是啥你都不知道?不是吧,不是吧
前言 最近写了很多数据库相关的文章,大家基本上对数据库也有了很多的了解,数据库本身有所了解了,我们是不是应该回归业务本身呢? 大家去了解过自己企业数据库的部署方式么?是怎么部署的,又是部署在哪里的?部署过程中可能会出现的问题有哪些? 是主从?还是双主?有没有分库?大的表做了分表没?等等...部署方式大概率也都是分库的,表数量级超千万基本上都开始分表了,考虑周全的企业,肯定也有数据库的冷备,热备,灾备,以及异地容灾等等。 我还记得我大学做项目,学校就是买了很多物理机,我们的项目和数据库都是部署在自己内部的服务器上的,那家伙一到夏天风我嗡嗡嗡的吹,烦死了,机房还很热。 但是我敢打赌,大家现在所在的企业,大概率都是使用了各种云服务厂商的服务部署方式,那就引入了今天的第一个思考。 为什么数据库要上云呢? 我们公司的大多数服务以及数据库都是在对应的云服务厂商的,那问题就来了,为啥都要上云呢? 在思考这个问题的时候,我第一时间想到了反证法,不上云的坏处是啥? 成本 相较于传统服务器需要购买、租用的方式,云服务器采用即用即收费的方式,减少购买成本,灵活扩展的容量可以按自己需求来定,不用前期估量需要用...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS7,8上快速安装Gitea,搭建Git服务器