随着业务的高速发展,我们团队在小程序端对接的业务越来越多也越来越繁杂。面对繁杂的业务需求,我们作为一个前端团队,一直在思考否能有更多的发挥空间,而云开发的出现,恰恰助力我们拓展前端的边界。
本文将主要记录我们团队在小程序云函数中的开发实践。
什么是云函数?
云函数(FaaS)是一段运行在云端的、轻量的、无关联的、并且可重用的代码。无需管理服务器,只需编写和上传代码,即可获得对应的数据结果。使用云函数可以使企业和开发者不需要担心服务器或底层运维设施,可以更专注代码和业务本身,也可以使代码进一步解耦,增加其重用性。
云函数有什么优势?
1. 简单易用
1.1 减少组件开销
使用云函数时,用户只需编写最重要的 “核心代码”,负载均衡、自动伸缩、网关等周边组件由平台负责,极大地降低了服务架构搭建的复杂性。
1.2 自动扩缩容
无需任何手动配置,云函数即可根据请求量自动横向扩缩。不管您的应用每天只有几个请求(如日志统计等定期事务),还是每秒有几千上万个请求(如移动应用的后端),云函数均可自动安排合理的计算资源满足业务需求。
2. 高效又创造性地开发
2.1 加速开发
云函数不要求特定框架或依赖(小程序云函数运行在 Node.js
环境中。我们可以如在 Node.js 环境中使用 JavaScript 一样在云函数中进行网络请求等操作。),开发者可以专注于核心代码的开发。同时开发人员可以组成多个小团队,单个模块的开发无需了解其他团队的代码细节。独立开发和迭代的速度变得前所未有的快,帮助用户把握住产品上线的黄金时间。
2.2 复用第三方服务
您可以使用云函数编写一些目的单一、逻辑独立的业务模块,因而可以完全复用已经成熟的第三方代码实现,例如,使用 npm 的 OAuth 实现登录模块。
2.3 简化运维
每个函数都是单独运行、单独部署、单独伸缩的,用户上传代码后即可自动部署,免除单体式应用部署升级难的问题。
3. 稳定可靠
3.1 高可用部署
云函数可以自动在每个地域中随机地选择可用区来运行。如果某个可用区因灾害或电力故障等导致瘫痪,云函数会自动地选择其他可用区的基础设施来运行,免除单可用区运行的故障风险。
3.2 与其他计算服务相辅相成
常驻的工作负载可以通过云服务器 CVM ,容器服务 TKE 来承载,而由事件触发的工作负载可以使用云函数。不同云服务满足不同的业务场景和业务需求,使得您的服务架构更加健壮。
4. 简化管理
4.1 简化安全配置
用户不再需要对 OS 入侵、登录风险、文件系统安全、网络安全和端口监听做复杂的配置和管理,一切交由平台处理,平台通过定制化的容器保证每个用户的隔离性。
4.2 可视化管理
用户可直接在控制台管理函数代码及函数何时运行(即函数触发器),无需复杂的配置文件即可一键部署和测试函数
5. 大幅度降低开销
5.1 永远不为空闲时间付费
函数在未执行时不产生任何费用,对一些并非常驻的业务进程来说开销将大大降低。函数执行时按请求数和计算资源的运行时间收费,价格优势明显,对初创期的开发者十分友好。
云函数的开发&发布
开通云开发、创建环境
在使用云开发能力之前需要先开通云开发。在开发者工具工具栏左侧,点击 “云开发” 按钮即可打开云控制台、根据提示开通云开发、创建云环境。默认配额下可以创建两个环境,各个环境相互隔离,每个环境都包含独立的数据库实例、存储空间、云函数配置等资源。每个环境都有唯一的环境 ID 标识,初始创建的环境自动成为默认环境。
指定云函数根目录、创建云函数
在项目根目录的 project.config.json
文件,新增 cloudfunctionRoot
字段,指定云函数的本地根目录:
{
"cloudfunctionRoot": "cloudfunctions/"
}
接着,我们在(微信开发者工具-编辑器)云函数根目录上右键,在右键菜单中,可以选择 【新建Node.js 云函数】,我们将该云函数命名为 test。开发者工具在本地创建出云函数目录,我们可以看到类似如下的一个目录结构:
-- cloudfunctions
|---- test
| |-- index.js
| |-- config.json
| |-- package.json
index.js
是当前云函数的主入口,类似如下的一个云函数模版:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return {
sum: event.a + event.b,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}
云函数的传入参数有两个,一个是 event 对象,一个是 context 对象。
- event 指的是触发云函数的事件,当小程序端调用云函数时,event 就是小程序端调用云函数时传入的参数,外加后端自动注入的小程序用户的 openid 和小程序的 appid。
- context 对象包含了此处调用的调用信息和运行状态,可以用它来了解服务运行的情况。
模版中所 require
的 wx-server-sdk 是一个帮助我们在云函数中操作数据库、存储以及调用其他云函数的微信提供的库。
接下来我就可以以 main
函数为入口编写我们的业务逻辑。云函数在云端是直接运行在 Node.js(本文发布时的Node.js 版本是 10.15)中的,所以原生支持 async
, await
等新规范中的 JS 语法。需要我们注意的是,每一个云函数是一个独立的项目,云函数在云端运行的时候是以一个独立的项目运行的。因此,我们在开发中不能引用函数目录外文件资源,当前函数所依赖的npm包也必须在当前目录中 npm install
。
config.json
是云函数的一些配置信息,用于配置 云接口权限和定时触发器 等配置信息。如下:
我们要在云端调用获取小程序码的接口,则需要在 config.json
中配置接口权限:
// config.josn
{
"permissions": {
"openapi": [
"wxacode.getUnlimited"
]
}
}
// index.js
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
try {
const result = await cloud.openapi.wxacode.getUnlimited({
scene: 'a=1'
})
return result
} catch (err) {
return err
}
}
本地调试
云开发提供了云函数本地调试功能,在本地提供了一套与线上一致的 Node.js 云函数运行环境,提供了 JS常见的单步调试/断点调试。
在微信开发者工具对应函数根目录上,右键选择【开启云函数本地调试】即可。
在本地调试界面中点击相应云函数并勾选【开启本地调试】方可进行该云函数的本地调试。取消勾选【开启本地调试】后可关闭对该云函数的本地调试。开启本地调试后,微信开发者工具模拟器中的对该云函数的请求、以及其他开启了本地调试的云函数的对该云函数的请求,都会自动请求到该本地云函数实例。
Tips: 若云函数中有使用使用到 npm 模块,需在云函数本地目录
npm install
后才可以开启本地调试。
云函数调用
在小程序中调用云函数:
// callback 风格
wx.cloud.callFunction({
// 云函数名称
name: 'add',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
success: function(res) {
console.log(res.result.sum) // 3
},
fail: console.error
})
// promise风格
wx.cloud.callFunction({
// 云函数名称
name: 'add',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
})
.then(res => {
console.log(res.result) // 3
})
.catch(console.error)
云函数调用云函数:
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const res = await cloud.callFunction({
// 要调用的云函数名称
name: 'add',
// 传递给云函数的参数
data: {
x: 1,
y: 2,
}
})
// 3
return res.result
}
部署及版本
部署
云函数的部署其实很简单,在需要部署的云函数的跟目录上右键选择 【创建并部署:所有文件】或者 【创建并部署:云端安装依赖(不上传node_modules)】即可。
需要特别注意的是,在部署云函数的时候一定要确认我们当前部署的【环境】,千万避免把测试环境的代码部署到线上环境!!!!
- 关于环境
小程序云函数默认可拥有最多两个环境,一个环境对应一整套独立的云开发资源,包括数据库、存储空间、云函数等资源。 在实际开发中,建议每一个正式环境(release)都搭配一个测试环境(test)。
右键 云函数的根目录 可切换环境
云函数部署
版本管理及灰度
云开发提供发布版本(快照)和多版本间调整流量比例的能力。我们可以借此能力实现灰度发布。
云函数版本
- 一个云函数可以发布多个版本,一个版本就是一个函数在当前时刻的快照,包含其代码和配置(超时时间、环境变量等)。
- 云函数始终存在一个
LATEST
版,即最新版。编辑器中上传云函数和在控制台更改配置始终更改LATEST
版本。
要进行灰度发布,只需更改版本之前的流量配比,即可实现灰度。
创建版本,灰度发布
日志及监控
监控
在云开发控制台的【监控图表】可以查看云函数的调用次数、运行时间、错误次数。
日志
小程序云开发的日志服务包含【日志】和【高级日志】两种。
- 日志: 在这里可以查看云函数的调用日志,方便开发者对开发调试。云函数的脚本错误等异常信息,以及我们
console.log()
可以在这里查询。
- 高级日志:提供了日志采集和检索分析等功能,方便开发者通过日志快速的发现和定位问题。每条日志可最长存储30天,超过 30 天的日志将被自动清理。
我们可以通过 wx-server-sdk
提供的 logger()
方法主动上报高级日志。
- 通过 logger() 方法取得 log 对象
- 调用 log 对象上的 log / info / warn / error (对应不同 level 的日志等级)方法,传入一个对象作为参数,每调用一次会产生一条日志记录
- 对象的每一个
对都会成为日志一条记录中的一个可检索的键值对,其中 value 不论值是什么都会被转成字符串。
如下:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
})
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
const log = cloud.logger()
log.info({
name: 'xx',
cost: 10,
attributes: {
width: 100,
height: 200,
},
colors: ['red', 'blue'],
})
// 输出到日志记录中会有这么一条记录:
// {
// "level": "info",
// "name": "xx",
// "cost": "10",
// "attributes": "{ width: 100, height: 200 }",
// "colors": "[ "red", "blue" ]"
// ..., // 其他系统字段
// }
return {
event,
}
}
告警设置
目前小程序·云开发提供两种告警配置:
- 基础告警:包括资源使用量提醒和计费相关信息,告警规则由系统配置,开发者可修改对应的告警渠道。
- 自定义告警:由开发者自定义告警条件。目前提供了 云函数错误次数和云函数运行时间 两个告警指标。
开发者可以通过微信开发者工具,在 【云开发控制台】 的 【设置】 页面中的 【告警设置】 中使用该功能。
更多信息参考 官方文档。
一些问题
云函数有着自己独特的优势,但是它同样有着让人不容忽视的一些问题:
不适合长时间运行应用
由于云函数的计费是根据运行时间和运行内存计费的,如果你的应用需要一直长期不间断的运行、处理大量的请求,那么你可能就不适合采用云函数。
冷启动时间
云函数在请求到来时才运行。这意味着,当应用不运行的时候就会进入 “休眠状态”,下次当请求来临时,应用将会需要一个启动时间,即冷启动。
AWS Lambda 的冷启动时间
函数之间无法共享信息
每一个云函数都是一个独立的项目,每一次运行都是独立运行的,因此云函数的之间信息共享异常困难。
复杂业务/逻辑不好实现
复杂业务场景下我们可能要拆分很多的函数,如何决定函数的粒度,并且评估,实现和测试?如何管理和维护多个函数之间的关系?如何关联管理?
总结
经过我们线上的一段时间的实践,小程序云函数的整体运行还是非常可靠的。可以利用云函数做一些特定的业务封装,减少对后端的依赖扩展我们前端的开发边界。
写于 2020年10月13日小程序 4834
如非特别注明,文章皆为原创。
转载请注明出处: https://www.liayal.com/article/5f8591fd7ff0f07e0ea449bd
记小栈小程序上线啦~搜索【记小栈】或【点击扫码】体验
~ 评论还没有,沙发可以有 O(∩_∩)O~