乐趣区

关于腾讯云:Serverless-多函数开发示例

01. 什么是 Serverless?

Serverless 的定义和了解在不同的角度和场景会有不同的解读,AWS 将 Serverless(在 AWS 云上) 定义为“是一种用于形容服务、实际和策略的形式,使您可能构建更麻利的应用程序,从而可能更快地翻新和响应变动”的一种服务。而红帽认为 Serverless 是“可使开发人员专一构建和运行利用,而无需治理服务器”的一种开发模型, 并进一步将 Serverless 的产品分为两类:BaaS(后端即服务,让开发人员拜访各种各样的第三方服务和利用) 与 FaaS(性能即服务,开发人员编写逻辑,部署到齐全由平台治理的容器中,而后按需执行) 两种状态。而 Serverless Framework 则认为 Serverless 是“一场由开发人员和企业推动, 让单个开发人员能够实现高流量的利用开发,同时只将精力集中在产生价值的方面”的静止,

不论哪个方面,哪种角度,Serverless 都具备以下独特特点:

  1. 疾速开发,疾速部署
  2. 按量付费,降低成本
  3. 主动扩容,无需保护

而目前都是基于各个云厂商的 FaaS 服务来实现,如:腾讯云的 SCF,AWS 的 Lambda,Azure 云的 Azure Funcitons 等。

Serverless 解决什么问题?

随着计算能力的增强,零碎复杂度的减少,用户规模的增长,软件问题(如下,也称为软件危机)也会产生指数型的增长。

  • 软件开发进度难以预测
  • 软件开发老本难以管制
  • 软件产品品质无奈保障
  • 软件产品难以保护

而 Serverless 则能够通过以下形式提出了对于软件危机问题的解决方案:

  • 通过函数形式将零碎性能拆分为更小的颗粒度,更便于设计,开发,测试和保护。
  • 通过按量计费大幅度缩小资源闲置时的开销费用,升高服务器老本。
  • 通过主动扩容以及云平台的反对,大幅缩小运维工作量以及软件维护老本。

同时在当初广泛提倡麻利工作形式的古代工作环境中,Serverless 也为疾速验证想法、迭代性能提供了开发方式的最佳实际,同时而不须要放心代码改变会影响零碎的其余性能,也无需思考部署前的服务器配置以及部署后的保护工作。

02. Serverless Framework

Serverless Framework 是业界十分受欢迎的无服务器利用框架,通过与泛滥一流云供应商如腾讯云,AWS 等的严密单干,为宽广开发者提供无需关怀底层基础设施,即可编写和部署代码的无服务开发体验。

Serverless Framework 同时提供资源管理、主动伸缩、统计分析等能力,让宽广开发者能够节俭运维老本,真正做到“按量付费”的同时,也无需破费精力解决日志收集、异样统计等工作。

Serverless Framework 通过 CLI 工具与腾讯云严密单干,为中国用户提供了基于组件(Serverless Components)的残缺解决方案。笼罩了无服务利用编码、测试、部署等全生命周期,同时切合中国用户的应用场景和习惯。

为什么选用 Serverless Framework?

通过 Serverless Framework 的短短几行配置文件和 CLI 工具,开发者就能够额定取得:

  • 在本地进行函数开发,并一键部署到云端,无需额定适配云函数,也无需登录控制台。
  • 反对将传统开发框架的利用(如:Express, Next.js, Flask, Laravel 等)部署为 Serverless 利用。
  • 在本地对函数代码进行调试,或应用近程开发模式在本地实时查看部署服务的日志输入,并进行调试。
  • 通过简略配置即可实现所有基础设施配置(如:API 网关、COS 存储、DB 链接等)
  • 疾速切换利用的部署环境(开发,演示,生产),地区。
  • 更具体轻松的理解利用状态,查看日志、报错统计等信息。

03. 多函数开发示例

本示例应用 Serverless Framework 的多函数组件(multi-scf)和 PostgreSQL 组件(postgresql)实现,实现以下 3 个 API 接口。

  • GET /todos/ 获取所有的 todo 事项
  • POST /todos/ 创立新的 todo 事项
  • POST /todos/{id}/actions/complete 实现 todo 事项

并应用 Serverless Framework 提供的 invoke 和 logs 性能进行调试以及查看生产环境实时日志。

本示例相干代码能够在 Git 仓库 中获取。

步骤 1: 装置 Serverless Framework

执行以下命令装置 Serverless Framework

$ npm install serverless -g

如果之前您曾经装置过 Serverless Framework,能够通过下列命令降级到最新版:

$ npm update serverless -g

此命令会装置最新的 Serverless Framework 到你的计算机,装置胜利后能够通过 serverless 或者 sls 开始应用 Serverless Framework

步骤 2: 初始化多函数我的项目

$ sls init multi-scf-nodejs --name sls-demo-msn-todo

此命令会应用利用模板 multi-scf-nodejs 初始化名为 my-multi-scf-demo 的利用目录。初始化胜利后该目录构造为

.
├── README.md
├── index.js
└── serverless.yml

这里的文件用处如下:

  • index.js:函数文件。
  • serverless.yml:Serverless Framework 配置文件。

    • app:利用名称,会作为利用辨认的惟一标识。
    • stage:应用环境,通过不同环境,部署不同的利用实例。
    • component:组件名称
    • name:组件实例名称
    • inputs:组件部署的输出参数

步骤 3: 链接数据库

因为 Serverless 是无状态的(运行后就会销毁),所以这里须要链接数据库用来长久化 todo 信息。增加数据库须要先借助 VPC 网络连接。

1. 增加 VPC

创立子目录 vpc 并在子目录中增加新的 serverless.yml 文件如下:

component: vpc # [必选]要应用组件,更多组件请查看 https://github.com/serverless-components
name: sls-demo-msn-vpc # [必选]组件实例名称

inputs:
  region: ap-guangzhou # 实例所属地区
  zone: ap-guangzhou-2 # 实例所属地区区域
  vpcName: ${name} # 实例名称,这里复用字段 name 作为名称。subnetName: sls-demo-msn-subnet # 子网的名称

更多 VPC 的配置内容,查看 VPC 公有网络 获取更多详情信息。

在子组件的配置文件中,app 名称会主动继承父目录的 serverless.yml 中的配置。同时同一个利用的 app 名称须要保持一致。

2. 增加数据库

创立子目录 db 并在子目录中增加新的 serverless.yml 文件如下:

component: postgresql #(必填) 援用 component 的名称,以后用到的是 postgresql 组件
name: sls-demo-msn-DB # (必填) 该 postgresql 组件创立的实例名称

inputs:
  region: ap-guangzhou # 实例所属地区
  zone: ap-guangzhou-2 # 实例所属地区区域
  dBInstanceName: ${name}-${stage} # 数据库实例名称惟一,且同一个数据库只能存在同一个 vpc 内。extranetAccess: true # 是否开启实例外网拜访
  vpcConfig: # vpc 网络配置
    vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc.vpcId} # 公有网络 Id
    subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc.subnetId} # 子网 Id

在数据库配置中增加数据库到 vpc 网络,这里应用输入变量 (output) 来动静获取 vpc 的 id 信息。

更多变量的配置内容,查看 Serverless 变量 获取更多详情信息。

更多 PostgreSQL 的配置内容,查看 PostgreSQL 数据库 获取更多详情信息。

在组件部署实现后,能够在组件目录内,应用 sls info 查看组件的输入变量,或者能够到腾讯云的利用控制台查看相干信息。

3. 初始化利用目录

  1. 创立子目录 src 并将创立生成的 index.js(重命名为todos.js)和 serverless.yml 挪动到目录中。
  2. src 目录中执行 npm init 初始化 Node.js 我的项目。
  3. src 目录中执行 npm i pg --save 装置数据库链接依赖包pg
  4. 在我的项目根目录增加根配置文件serverless.yml,文件如下:
app: sls-demo-msn-todo-3e5a2134 # 利用惟一辨认标识,同账号下须要放弃惟一。stage: dev # 利用部署环境名称,这里应用环境变量 STAGE 的值。

根目录的配置文件信息会被子组件继承,不须要在子组件中反复定义。(仅限于 app 与 stage)。

最终实现的我的项目目录构造如下:

.
├── README.md
├── db # 数据库
│   └── serverless.yml # 数据库配置文件
├── serverless.yml
├── src # 多函数利用
│   ├── node_modules
│   ├── package-lock.json
│   ├── package.json # Node.js 依赖文件
│   ├── serverless.yml # 多函数利用配置文件
│   └── todos.js # todo 利用主文件
└── vpc # vpc
    └── serverless.yml # vpc 配置文件

4. 批改多函数利用配置

在多函数目录 src 内批改配置文件如下:

component: multi-scf
name: sls-demo-msn

inputs:
  src:
    src: ./
    exclude:
      - .env
      - "node_modules/**" # 部署时疏忽 node_modules 目录中所有文件,以放慢部署速度
  environments: # 利用环境变量信息
    - key: PG_CONNECT_STRING
      value: ${output:${stage}:${app}:sls-demo-msn-DB.private.connectionString}
  region: ap-guangzhou
  runtime: Nodejs12.16
  memorySize: 128
  vpc: # vpc 网络配置
    vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc.vpcId} # 公有网络 Id
    subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc.subnetId} # 子网 Id
  installDependency: true # 是否在线装置依赖
  timeout: 6 # 默认超时工夫(秒)functions: # 多函数定义
    allTodo: # 函数别名
      handler: todos.all # 处理函数
      memorySize: 256 # 自定义次函数的内存空间
    addTodo:
      handler: todos.add
      timeout: 9 # 自定义此函数的超时工夫(秒)completeTodo:
      handler: todos.comp
      timeout: 9
  triggers: # 触发器配置
    - type: apigw
      parameters:
        name: todosAPIGW
        protocols:
          - https
          - http
        apis: # API 配置
          - path: /todos/ # 路由门路
            method: GET # 路由办法
            function: allTodo # 路由处理函数别名
          - path: /todos/
            method: POST
            function: addTodo
          - path: /todos/{id}/actions/complete
            method: POST
            function: completeTodo
            param: # 动静路由参数配置
              - name: id
                position: PATH
                required: true
                type: number
                desc: Todo ID

这里批改次要内容有:

  • 应用 installDependency 开启部署后依赖主动装置并疏忽 node_module 目录下的全副文件(无需上传 node_modules,放慢部署)
  • 应用 vpc 增加 vpc 网络并链接到我的项目同一个 vpc 网络中。
  • 应用 environments 增加我的项目环境变量,并应用输入变量(output)来动静生成数据库连贯字符串。
  • 应用 functions 来申明我的项目中的函数及其别名。
  • 应用 triggers 申明函数的触发器,并在触发器的 apis 中配置各个函数对应的门路,以及参数信息。

更多函数开发的配置内容和详情,查看 PostgreSQL 数据库 获取更多详情信息。

更多 函数开发 的阐明内容,查看 函数开发 获取更多详情信息。

步骤 4: 开发性能

批改 todos.js 并实现相干性能的开发,最终该文件代码如下:

"use strict";
const {Client} = require("pg");

const client = new Client({connectionString: process.env.PG_CONNECT_STRING,});

/**
 * 初始化数据库和表构造
 */
const initDB = async () => {
  const isConnected = client && client._connected;

  if (!isConnected) {await client.connect();

    await client.query(`
    CREATE TABLE IF NOT EXISTS todo (
      ID              SERIAL          NOT NULL,
      TITLE           VARCHAR         NOT NULL,
      NOTE            TEXT,
      IS_COMPLETE     BOOLEAN         DEFAULT FALSE
    );`);
  }
};

/**
 * 获取所有 Todo 事项
 */
exports.all = async (event, context) => {
  // async 须要敞开事件循环期待,以防止日志记录超时或函数无返回的问题。context.callbackWaitsForEmptyEventLoop = false;
  await initDB();

  const {rows} = await client.query({text: "SELECT * FROM todo"});

  return {
    message: "Tencent SCF execute successful!",
    data: rows,
  };
};

/**
 * 增加新的 Todo 事项
 */
exports.add = async (event, context) => {
  // async 须要敞开事件循环期待,以防止日志记录超时或函数无返回的问题。context.callbackWaitsForEmptyEventLoop = false;
  const {title, note} = JSON.parse(event.body);
  if (!title) {
    return {
      statusCode: 400,
      message: "Missing Todo Title",
    };
  }

  await initDB();
  const {rowCount} = await client.query({text: "INSERT INTO todo (title, note) VALUES($1, $2)",
    values: [title, note],
  });

  return rowCount === 1
    ? {
        statusCode: 201,
        message: "Todo added success.",
      }
    : {
        statusCode: 400,
        message: "Todo added failed.",
      };
};

/**
 * 实现指定 Todo 事项
 */
exports.comp = async (event, context) => {
  // async 须要敞开事件循环期待,以防止日志记录超时或函数无返回的问题。context.callbackWaitsForEmptyEventLoop = false;
  const todoId = event.pathParameters.id;

  if (!todoId && !isNaN(todoId)) {
    return {
      statusCode: 400,
      message: "Missing Todo Id",
    };
  }

  await initDB();
  const {rowCount} = await client.query({
    text: "UPDATE todo SET is_complete = true WHERE id=$1",
    values: [todoId],
  });

  return rowCount === 1
    ? {
        statusCode: 200,
        message: "Todo Complete success.",
      }
    : {
        statusCode: 400,
        message: "Todo Complete failed.",
      };
};

步骤 5: 调试性能

1. Invoke 调试

要调试代码除了应用第三方开发工具通过配置的 API 网关 url 调试,还能够应用 Serverless Framework 的 Invoke 性能 或 近程调试 性能. 这里应用 invoke 性能演示如何调试函数性能。

invoke 和 近程调试性能 须要在组件的目录内执行。

2. 获取全副 Todo

在 src 目录下执行

$ serverless invoke -f allTodo

执行后能够失去的后果

应用受权信息 default 受权中,如果须要应用长期密钥,请应用 --login 从新登陆
billDuration:      36
duration:          36
errMsg:
functionRequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3
invokeResult:      0
log:
  """
    START RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3
    Event RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3

    END RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3
    Report RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3 Duration:36ms Memory:256MB MemUsage:11.3984MB
  """
memUsage:          11952128
---------------------------------------------
Serverless: 调用胜利

{
  message: 'Tencent SCF execute successful!',
  data: []}

在 invoke 返回的后果中,会蕴含函数执行后的 meta 信息,如运行工夫,谬误,RequestId,执行的日志 和函数返回的后果。

3. 创立新的 Todo

在 src 目录下执行

$  serverless invoke -f addTodo --data "{\"body\":\"{\\\"title\\\":\\\"Create multi-scf project demo\\\",\\\"note\\\":\\\"Todo App with postgreSQL\\\"}\"}"

执行后能够失去的后果

应用受权信息 default 受权中,如果须要应用长期密钥,请应用 --login 从新登陆
billDuration:      35
duration:          35
errMsg:
functionRequestId: 93f50016-064f-468d-9e98-31645fc254fd
invokeResult:      0
log:
  """
    START RequestId: 93f50016-064f-468d-9e98-31645fc254fd
    Event RequestId: 93f50016-064f-468d-9e98-31645fc254fd

    END RequestId: 93f50016-064f-468d-9e98-31645fc254fd
    Report RequestId: 93f50016-064f-468d-9e98-31645fc254fd Duration:35ms Memory:128MB MemUsage:11.293MB
  """
memUsage:          11841536
---------------------------------------------
Serverless: 调用胜利

{
  statusCode: 201,
  message: 'Todo added success.'
}

步骤 6:部署和日志

1. 部署代码到生产环境

应用上面命令能够疾速部署我的项目到生产环境(这里命名生产环境为prod

$ serverless deploy --stage prod

2. 即时查看生产环境日志

在我的项目目录 src 中执行以下命令能够查看我的项目的即时日志信息

$ sls logs --tail -f allTodo --stage prod

以下是返回后果:

应用受权信息 default 受权中,如果须要应用长期密钥,请应用 --login 从新登陆

serverless ⚡components
Action: "logs" - Stage: "prod" - App: "sls-demo-msn-todo-3e5a2134" - Name: "sls-demo-msn"

START RequestId:6f31857109130f092c547337c073ea91

Response RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2 RetMsg:{"message":"Tencent SCF execute successful!","data":[{"id":1,"title":"Create multi-scf project demo","note":"Todo App with postgreSQL","is_complete":false}]}
END RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2
Report RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2 Duration:4ms Memory:256MB MemUsage:12.113281MB

Response RequestId:485a87cfc6ad385b7e9c84343962391b RetMsg:{"message":"Tencent SCF execute successful!","data":[{"id":1,"title":"Create multi-scf project demo","note":"Todo App with postgreSQL","is_complete":false}]}
END RequestId:485a87cfc6ad385b7e9c84343962391b
Report RequestId:485a87cfc6ad385b7e9c84343962391b Duration:4ms Memory:256MB MemUsage:11.886719MB

START RequestId:0ede6d26dca55362a701c10ff51c9021


Serverless › 监听中 ...

总结

感激长久以来对 Serverless Framework 反对的宽广开发者,将来咱们也会持续迭代产品,推出新性能,改良产品应用体验,最终咱们会为中国的开发者打造一套符合中国开发者习惯的无服务器开发的残缺解决方案。

也欢送大家到 Serverless 中文社区分享教训和想法以及反馈问题和 BUG。

Serverless 中文社区:https://github.com/serverless/serverless-tencent/discussions

最初心愿大家能够参加咱们的有奖考察问卷:https://www.surveymonkey.com/…

One More Thing

立刻体验腾讯云 Serverless Demo,支付 Serverless 新用户礼包 👉 腾讯云 Serverless 老手体验。

退出移动版