基于 serverless 开发后端服务,前端项目部署在 serverless 上
- 目标:深入理解 serverless 的原理以及实战应用
serverless
serverless 基本介绍
- 传统高并发架构(serverFull)
- serverless:是无服务器架构思想,并非是说不依赖服务器,而是让开发者更多精力聚焦在业务代码,而无需关注服务器部署,负载均衡,数据存储,并发等一些列服务器问题。
- 直白的个人认知:
- 所谓的 serverless 即把传统 IT 架构方案,从线下完全抽象到云端,数字化配置即可。
- 把物理服务配置发展到线上可定制化的数据驱动服务。
- 从 devops 体系也发展成云端可集成运维方案
- 传统架构模式,要 控,容灾备份,高并发,弹性伸缩等等需求统统成为可配置,可数字化集成的线上技术。
- 说白了传统架构方案有的,serverless 全部基于云服务统统涵盖,甚至于基于云计算的实时感知,在降低风险,降低成本,提升效率等方面,目前处于最优方案。我们只需要关注代码,其余统统托管,只需要按量付费,便可实现弹性伸缩
- 初步可以理解为 faas 和 baas 的结合体:函数即 faas,服务即 baas
- 基本的开发/发布流程非常简洁
serverless 基本特点
- serverless 核心特点:第三方平台,由事件触发,存在于无状态(stateless),暂存计算容器内(只存在于调用过程中 ),微服务,按量付费,弹性伸缩
- serverless 相比传统 serverFull 特点
- 资源分配:
- 无需关心项目运行时所需资源,如:磁盘大小,内存损耗以及其他服务配置
- 计费:
- serverless 架构中,计费方式按照实际用量计费,如果函数调用次数,运行时常,精确到毫秒,有很多平台有免费额度,甚至有些访问量不大的中小项目,可以免费部署。
- 弹性伸缩:
- 自动化,更精准的根据业务实际情况和发展趋势,用户无感知自动伸缩,极限状态甚至可以允许缩容为 0,那么费用即为 0
谁在用 serverless?
- 中大厂基本人手一份
应用热度
- 以基于腾讯云的 serverless 框架为例
- https://cn.serverless.com/
- 周下载量:120w 左右
serverless 的能力概述
- 计算能力
- 资源按需分配
- Mwm:租户级强镜隔离。Docker:进程级隔离
- Mwm+Docker:轻量级资源,毫秒级启动
- 实时无感知扩容/阶梯缩容
- 按需收费
- 系统运维能力
- 性能保障
- 整个链路耗时毫秒级,并支持 VPC(私有网络)内网访问
- 安全保障
- 资源对用户不可见,安全由托管方如(腾讯云)提供专业保障
- 提供进程级和用户级安全隔离
- 访问控制管理
- 自动性扩缩容
- 根据 CPU 和网络 io 的实际情况自动扩容底层资源
- 根据请求数量,自动扩缩函数实例,业务高峰扩容,满足并发需求,低峰缩容,释放资源,降低成本
- 自愈能力
- 确保每一次请求都是健康的函数实例
- 关于函数启动方式
- serverless 中函数被第一次调用会执行冷启动
- serverless 中函数被连续调用会执行热启动
- 冷启动:当该函数第一次被请求时,相当于在服务器中开辟一块空间去运行该函数实例,相当于把函数放到虚拟机中运行,每次运行就要先启动虚拟机,加载该函数。不过现在这个过程都是毫秒级,无需担心性能。只不过 session 在这个过程中有可能丢失,所以建议有一套针对 session 的存储策略
- 热启动:当该函数持续被调用时,那么第一次冷启动创建的函数实例将不会释放,下次请求由之前已创建的实例来运行。这个过程也类似于打开虚拟机之后运行完该函数,然后虚拟机待机,下回可以直接触发。这样省去冷启动的耗时的环节,但长期激活状态,相比而言系统开销就会更大一点。
- 业务运维能力
- devops 集成
- 错误收集,故障排查,警报监控等等
- vscode 插件,云 api,sdk 等等
serverless 服务商
- 亚马逊:https://aws.amazon.com/cn/lambda
- 谷歌: https://cloud.google.com/functions
- 微软:https://www.azure.cn
- 阿里:https://www.aliyun.com/product/fc
- 腾讯:h
- 华为:https://huaweicloud.com/product/functiongraph.html
怎么选服务商
- 优先国内服务,方便快速,文档友好
- 腾讯云和 serverless 合作开发集成 serverlessFramework,开发可选性强,兼容性好,部署成本低
- 当然,华为云和阿里云也很优秀
serverless 熟悉
- 线上https://console.cloud.tencent.com/scf 直接操作
- 函数服务->新建->选模版->选类型:如 web(默认支持:http/https)
- serverless Freamwork
- serverless freamwork 是由 serverless 公司推出的开源的 serverless 应用开发框架
- 由 serverless freamwork plugin 和 serverless freamwork components 组成
- serverless freamwork plugin 是个函数管理工具,使用该工具可以轻松部署,删除,触发,回滚函数,也可以查看函数日志,函数信息,函数数据等等。
- serverless freamwork components 是个组件集,包含各类组件比如:cos,scf,apigateway。还有各种扩展组件,如从 cos 扩展而来的 website 用于部署静态网站,还有其他的框架级组建如 express,koa 等等
- 详情:https://cn.serverless.com/
serverless 开发环境实操
- webcli 方式-不推荐
- https://console.cloud.tencent.com/sls 到这浪
- 基于 vscode 插件开发云函数 Tencent Serverless Toolkit for VS Code(当然其他的比如阿里也有对应的插件)
- Tencent Serverless Toolkit for VS Code:是腾讯 serverless 产品 vscode 的插件,该插件可以让你在本地运行 serverless 项目并且可以轻松部署到云端
- 搜索该插件-安装你就会用了
- 注意修改本地配置文件「path:/」,不然代码直接部署会访问不到
- serverless cli (freamwork)- 推荐
- npm install -g serverless 安装
- sererless -v 看下版本
- 初始化 serverless 项目命令:
- 使用模板创建 serverless 应用并指定名称(此处以 express 为例,至于你想要哪种:serverless)
- serverless init express-starter --name 项目名称
- sls init express-starter --name 项目名称
- 部署:serverless deploy
- 访问函数,完事
- 本地调试:node app.js 或者 nodemon app.js 本地运行即可
配置静态 web 服务
提高发布速度,部署自动安装依赖:node_modules(看个人习惯)
- serverless.yml
- 配置 exclude
exclude:
- .env
- node_modules // 发布是排除该文件夹就会提升发布速度,部署需要到服务器上开启部署安装依赖,手动部署
- express 模版静态服务
- app.js
- website 新建文件夹中放静态网页资源,文件夹名称随意
- 默认读取 index.html
- https://github.com/serverless-components/tencent-express
// 静态web服务
app.use(express.static("website"));
- express 配置 ejs 模版引擎
- 安装 ejs 模版引擎
- npm i ejs --save
- 配置引擎
const ejs = require("ejs");
// 配置ejs模版引擎,默认读取根目录下views中的html
app.engine("html", ejs.__express);
app.set("view engine", "html");
- 渲染数据
app.get(`/`, (req, res) => {
// res.sendFile(path.join(__dirname, "index.html"));
res.render("index", {
// views下的index渲染title
title: "你大爷",
});
});
<!-- 通过ejs渲染 -->
<body>
引擎<%=title%>
</body>
- koa 模版静态服务
- 安装静态服务插件:cnpm install koa-static --save
- website 新建文件夹中放静态网页资源,文件夹名称随意
- https://github.com/serverless-components/tencent-koa
const static = require("koa-static");
app.use(static("website"));
- serverless 部署 eggjs
- egg 框架中自带静态资源,可以直接访问
- serverless init egg-starter --name 项目名称
- https://github.com/serverless-components/tencent-egg
- servlerless 服务器只有根目录 tmp 有写入权限,所以日志存储需要特殊指定
const config=export={
env:'prod',
rundir:'/tmp',
logger:{
dir:'/tmp'
}
}
部署前端项目(基于对象存储)
- vue2.0 项目发布
- serverless init vue-starter --name 项目名称
- 初始化项目
- serverless deploy
- 先在根目录打包出 dist,接着部署到服务器
- 对象存储-存储桶列表即可查看,列表名称可以通过:yml 文件 bucketName 进行修改
- 比如 http/https 的问题可以在 yml 中配置,也可以在对象存储-存储桶列表-基础配置-静态网站中修改
- 比如 错误页默认走 serverless 自带的 error 页面,可以在对象存储-存储桶列表-基础配置-静态网站中修改,改成 index,使用项目的静态路由
- 关于编译命令和发布包的名称设定在 yml 配置
- 部署 vue3.0
- 简单,把命令生成的脚手架内容全部删掉,只保留 yml 文件,然后把你的项目复制进来即可
- 部署 react
- 步骤与上面一致
- 部署 angular
- https://github.com/serverless-components/tencent-website
- 说白了,就是生成一个容器,保留 yml 然后把你的项目放进去即可
- 配置细节直接在 yml 中直接配置
- 如果无法访问看看发布的文件包的目录层级在 yml 文件中配置即可
serverless 中 node 配置 mysql,mongodb,私有网络(vpc)
- 操作 mysql
- 注意点
- 局域网部署要求:云数据库在选择时,选择区域时与当前 serlveless 服务器已在一个区域比如都在上海,以应对 VPC 服务部署的需求
- 直接函数服务-新建模板-mysql-选择 node 版本,如果需要局域网就记得选择局域网,如果没有则需要新建局域网
- 新建 mysql/或者数据库集群,开放公网/vpc,如果开放 vpc 选择你之前的新建的局域网,同时开放公网和局域网
- 如果想通过 api 方式调接口,回到函数服务,创建触发器,通过 api 访问即可
- 回到函数服务选择 node-mysql 实例,index.js 连接数据库
exports.main_handler = async (event, context, callback) => {
const mysql = require("mysql");
const connection = mysql.createConnection({
host: "集群/数据库公网地址", // The ip address of cloud database instance, 云数据库实例ip地址
user: "账号名", // The name of cloud database, for example, root, 云数据库用户名,如root
password: "数据库密码", // Password of cloud database, 云数据库密码
database: "链接数据库", // Name of the cloud database, 数据库名称
port: 端口号,
});
// 链接数据库
connection.connect();
// 测试sql
const querySql = `SELECT * from users`;
let queryResult = await wrapPromise(connection, querySql);
connection.end();
return queryResult;
};
- vpc 访问(更快 )
- 云函数和数据库的区域必须保持一致
- 去数据/集群复制私有网络的 IP/端口,去函数服务 index 中替换即可
- mongodb 配置
- 其实一样,选择 mongodb 示例
- 新建 mongodb 数据库
- 链接方式大同小异
COS 对象存储
- 对象存储(cloud object storage),存储海量文件的“分布式存储服务”
- 优点:高可扩展,低成本,可靠安全
- 通过控制台,api,skd 以及工具等轻松接入 cos,进行多格式文件进行,上传,下载,管理,实现海量文件存储管理
- 基础操作: https://cloud.tencent.com/document/product/436/8629
实操
- 创建 demo 文件夹,mkdir node-cos
- 初始化 npm 环境,npm init --yes
- 新建 app.js,touch app.js
- npm i cos-nodejs-sdk-v5 --save
app.js 配置 cos
// SECRETID 和 SECRETKEY请登录 https://console.cloud.tencent.com/cam/capi 进行查看和管理
var COS = require("cos-nodejs-sdk-v5");
var cos = new COS({
SecretId: "你自己的SecretId",
SecretKey: "你自己SecretKey",
});
对象存储/对象存储列表,创建存储容器
- 创建完成后返回存储列表
配置上传
cos.putObject(
{
Bucket: "file-storage-test-1314081338" /* 存储桶名称 */,
Region: "ap-guangzhou" /* 所属地域 */,
Key: "./imgs/" /* 目录或者指定文件名称 */,
StorageClass: "STANDARD",
Body: fs.createReadStream("./imgs/test.jpeg"), // 上传文件路径
onProgress: function (progressData) {
console.log(JSON.stringify(progressData));
},
},
function (err, data) {
console.log(err || data);
}
);
// 执行node app.js,打开存储桶,对应文件夹即可看到上传资料
serverless 应用中实现 cos 上传
- express
- 基于 body-parser 解析 body 资源,可用过 req.body 获取表单资源
- pnpm install body-parser -S
- 安装 multer 图片上传插件
- pnpm install multer -S
- 如果是页面 form 需要配置 enctype=“multipart/form-data”
- 配置内存存储引擎,将文件存储在内存中保存一份 buffer(备上传)
- 拿到 buffer 存储到云端
- 安装 cos 插件
- pnpm i cos-nodejs-sdk-v5 --save
- 添加对应配置项
// app.js
const { uploadImg } = require("./cos.config");
// 上传图片插件
const multer = require("multer");
// 解析body插件
const bodyParser = require("body-parser");
// 配置body-parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 配置图片上传插件
const storage = multer.memoryStorage();
const uploadCloud = multer({ storage });
// 上传方法
// single()内的参数必须跟提交过来的字段名保持一致
app.post("/uploadFile", uploadCloud.single("avatar"), (req, res) => {
console.log("提交过来的文件", req.body, req.file);
uploadImg(req, res);
});
- 封装 cos.config.js
var COS = require("cos-nodejs-sdk-v5");
const fs = require("fs");
var cos = new COS({
SecretId: "你自己的id",
SecretKey: "你自己的key",
});
const uploadImg = (req, res) => {
// 上传
cos.putObject(
{
Bucket: "file-storage-test-1314081338" /* 存储桶名称 */,
Region: "ap-guangzhou" /* 所属地域 */,
Key:
"./imgs/" +
Date.now() +
"-" +
req.file.originalname /* 目录或者指定文件名称 */,
StorageClass: "STANDARD",
Body: req.file.buffer, // 上传文件对象
onProgress: function (progressData) {
console.log(JSON.stringify(progressData));
res.send(res.send(req.body));
},
},
function (err, data) {
console.log(err || data);
}
);
};
module.exports = {
uploadImg,
};
- 发布线上并测试
- 如果图片上传失败,去 serverless.yml 中查看一下网关
apigw:
# isBase64Encoded: true
serverless 中配置域名来访问应用和存储资源(私有备案中,待补充)
- 域名解析
- 注册域名
- 将域名解析指定 serverless 服务
- 自定义域名:自定义路径映射
- 使用 HTTPS
- 安装证书:腾讯云搜索:ssl,去购买“免费版 ”
- 输入绑定域名