乐趣区

如何将-Web-框架迁移到-Serverless

Serverless 通常翻译为「无服务架构」,是一种软件系统设计架构思维和办法,并不是一个开发框架或者工具。他的呈现是为了让开发者更加关注业务的开发,而将繁冗的运维和部署交给云厂商。Serverless 由 Faas 和 Baas 组成,Faas 为开发者提供业务运算环境,而后与 Baas 提供的数据和存储服务,进行交互,从而提供与传统服务统一的体验。然而因为 Faas 是无状态的,并且其运行环境是有读写限度的,最重要的是它是基于事件触发的。因而如果传统 Web 服务想迁徙到 Serverless 上,是须要进行相干革新和非凡解决的,为此迁徙老本是必不可少的。本文将具体帮忙大家分析下,如何 Serverless 化传统的 Web 服务。

读完本文将理解到:

  1. 传统 Web 服务特点
  2. Serverless 实用场景
  3. Web 框架如何迁徙到 Serverless
  4. 应用 Serverless Components 疾速部署 Web 框架

传统 Web 服务特点

Web 服务定义:

Web 服务是一种 面向服务的架构 (SOA) 的技术,通过规范的 Web 协定提供服务,目标是保障不同平台的应用服务能够互操作。

日常生活中,接触最多的就是基于 HTTP 协定的服务,客户端发动申请,服务端承受申请,进行计算解决,而后返回响应,简略示意图如下:

传统 Web 服务部署流程:通常须要将我的项目代码部署到服务器上,启动服务过程,监听服务器的相干端口,而后期待客户端申请,从而响应返回处理结果。而这个服务过程是常驻的,就算没有客户端申请,也会占用相应服务器资源。

个别咱们的服务是由高流量和低流量场景交替组成的,然而为了思考高流量场景,咱们须要提供较高的服务器配置和多台服务进行负载平衡。这就导致服务处在低流量场景时,会多出很多额定的闲置资源,然而购买的资源却须要依照高流量场景进行付费,这是十分不划算的。

如果咱们的服务能在高流量场景主动扩容,低流量场景主动缩容,并且只在进行计算解决响应时,才进行免费,而闲暇工夫不占用任何资源,就不须要免费呢?

答案就是 Serverless

Serverless 实用场景

下面曾经提到了 Serverless 的两个外围特点:按需应用和免费 主动扩缩容。而且近几年 Serverless 的利用也越来越宽泛,然而它并不是银弹,任何技术都是有它的适宜场景和不适宜场景。咱们不能因为一项技术的炽热,而自觉的追捧。Serverless 是有它的局限性的,个别 Serverless 适宜如下几种场景:

  1. 异步的并发,组件可独立部署和扩大
  2. 应答突发或服务使用量不可预测
  3. 无状态,计算耗时较短服务
  4. 申请延时不敏感服务
  5. 须要疾速开发迭代的业务

如果你的服务不满足以上条件,笔者是不举荐迁徙到 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

代码实现

原理大略介绍分明了,咱们的外围实现代码须要以下三步:

  1. 通过 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;
}
  1. 将 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;
  }
}
  1. 将 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 框架,比方 PythonFlask 框架,原理都是一样的,外围只须要做到 将 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.tenc…

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

传送门:

  • GitHub: github.com/serverless
  • 官网:serverless.com

欢送拜访:Serverless 中文网,您能够在 最佳实际 里体验更多对于 Serverless 利用的开发!


举荐浏览:《Serverless 架构:从原理、设计到我的项目实战》

退出移动版