关键词:
简介:当下,Serverless 概念很火,很多同学被 Serverless 的优势吸引过来,比如它的弹性伸缩,免运维,高可用,资费少。但真正使用起来去落地的时候发现问题很多,大型项目如何组织函数,性能优化怎么做,怎么做Serverless调试,数据库,共享会话怎么加等等。上周,Serverless Devs 2.0 正式版全新发布。Serverless Devs 2.0 在平台能力、应用模板以及开发者套件方面能力提升。本文以 Serverless Devs 的应用中心(web 版)为案例,来看开箱实践方案。
当下,Serverless 概念很火,很多同学被 Serverless 的优势吸引过来,比如它的弹性伸缩,免运维,高可用,资费少。但真正使用起来去落地的时候发现问题很多,大型项目如何组织函数,性能优化怎么做,怎么做Serverless调试,数据库,共享会话怎么加等等。上周,Serverless Devs 2.0 正式版全新发布。Serverless Devs 2.0 在平台能力、应用模板以及开发者套件方面能力提升。接下来,以 Serverless Devs 的应用中心(web 版)为案例,来看开箱实践方案。
Serverless 函数代码组织
如果想充分利用 Serverless 的能力函数是最佳方案,可以最大程度减少冷启动时间,践行用完即走的理念,保障用户体验的同时,最大程度减少成本,不过对于中大型项目而言,以单函数的方式组织代码,在维护上无疑是一个巨大挑战,可能一个应用会有数百个函数,维护成本极高也极易出错。
最好的方式是用框架的方式组织代码,以函数的方式部署执行。框架组织代码需要做业务的划分,比如电商包含商品,订单,用户等服务,都放到一个框架里面并通过函数去部署执行的话明显太大了。最好就是像微服务一样,独立业务的接口可以在同一个函数中,每一个业务有自己的独立域名,再通过内部路由访问具体的业务服务。
这样做可以最大限度的利用函数能力,并且维护得来相对容易一些。
我们把 Serverless Hub 的应用市场作为一类场景,进行了统一划分,具体的函数调用如下实现(完整的代码目录 git)
const http = require('@serverless-devs/dk'); const searchApp, getAppDetail, getSpecialDetail, getSpecialApp, getCategorys, getTags = require('./services'); http .get("/appCenter/getSpecial", async (ctx) => const data = await getSpecialApp(ctx); ctx.body = data; ) .post("/appCenter/getSpecialDetail", async (ctx, next) => const data = await getSpecialDetail(ctx); ctx.body = data; ) .post("/appCenter/getAppDetail", async (ctx) => const data = await getAppDetail(ctx); ctx.body = data; ) .get("/appCenter/getCategory", async (ctx) => const data = await getCategorys(); ctx.body = data; ) .get("/appCenter/getTags", async (ctx) => const data = await getTags(); ctx.body = data; ) .post("/appCenter/getApps", async (ctx) => const data = await searchApp(ctx); ctx.body = data; ) .get("/", async (ctx, next) => let result = "Hello ServerlessDevs"; ctx.body = result; ) http.app.use(http.routes()); exports.handler = http();
代码使用了 Serverless Devs 提供的 @serverless-devs/dk ,我们对标准的前端框架进行了核心封装,比如 express,koa 等,你可以继续使用习惯的 web 框架进行开发工作,最后通过 s 工具进行函数部署。s.yaml 的配置如下:
edition: 1.0.0 # 命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范 name: fc-http-demo # 项目名称 access: default # 秘钥别名 vars: services: serverlesshub: component: devsapp/fc # 组件名称 props: region: cn-hangzhou service: name: myserverlesstest description: demo for fc-http component internetAccess: true function: name: myhub description: this is a test runtime: nodejs12 codeUri: ./code handler: index.handler memorySize: 128 timeout: 10 triggers: - name: httpTrigger type: http config: authType: anonymous methods: - GET - POST customDomains: - domainName: auto protocol: HTTP routeConfigs: - path: /* # 函数计算FC组件文档参考地址:https://github.com/devsapp/fc
如果你想再增加一个服务业务,可以水平扩展一个新的服务配置,并且可以用同样的代码包去实现。
性能优化
通常 Serverless 应用的最大耗时都在 冷启动时间上,就以阿里云 FC 为例,如果我们的应用以容器的方式进行部署,冷启动时间会比较长可能是 1 分钟或者更多,即使采用镜像加速也仅能缩短到几十秒以内,所以如果项目不是特别大(AI 类应用的包大小可能会达到 G 级别),都建议以 原生runtime 的方式去做。拿我们上面的 serverless hub 为例就是最终运行到 nodejs12 runtime,冷启动时间 1~2s
热启动则缩短到150ms
对于这类非高频访问的站点而言还是比较适合的,另外你可以根据需要在具体的某个时间点通过添加预留的方式保持高性能的访问效果。
当然,冷启动这块需要云厂商的进一步优化把他做到极致,最终才能真正让 Serverless 完美。
端云调试
调试始终是 Serverless 应用的最棘手的部分,我们开发的应用是在本地,部署的应用是在线上。并且线上的环境跟本地开发环境有着巨大的差异,通常我们只能通过在线打印输出,然后还得通过日志平台查看日志判断问题,再回来本地修改代码,一来一回耗时非常巨大,而且效果也不好。Serverless Devs 提供了自己的解决方案,我们巧妙的设计了一个在线的辅助函数,辅助函数完整复刻线上代码,然后通过本地跟辅助函数建设通道实现本地的代码调试效果。
基于这样的能力我们再来看看具体怎么在 Serverless Hub 实施的, 本次演示使用的是Serverless Desktop, 大家可以尝试跟着我的操作步骤进行使用:
1、新建一个Serverless 应用,并把它部署到线上
我们可以通过 Serverless Desktop 的应用市场搜索 xxx 应用模板,然后加载到本地,然后通过可视化配置部分修改相应的服务和函数内容,进行部署。
2、进入工作空间->应用管理->应用详情->端云调试
按照提示准备好前置条件,比如安装docker demon 指定调试端口,启动资源准备,这个时候会创建辅助函数,同时构建 vscode 的 debug 文件。
启动好之后,使用 vscode 打开工程目录,查看debug配置文件.vscode/launch.json
以这个启动 debug 模式
3、发起调用
切换到"本地调试配置"面板,点击"发起调用"
可以发现 vscode 触发调试
调试结束回到 Serverless Desktop 页面,我们可以看到输出效果:
这里我们发起调用是向这个服务的根目录发起,如果我们想向其他的路由地址发起调用该怎么操作呢?我们可以复制发起调用后输出的基础地址。
然后贴到 postman, 再往后拼接上我们的测试路由地址,比如,想访问"/appCenter/getSpecial",可以拼接成"<基础地址>/appCenter/getSpecial"然后"Send"这个请求。
通过这样的方式我们可以深入细节知道每一行代码的调用问题到底出在哪里,极大的提高了我们的开发效率。
4、清空环境
调试结束后不要忘了清楚调试环境,包括关闭本地的容器地址,以及清理线上的函数。
综上我们完成了一次完整的调试过程。
数据库使用
Serverless 一大特色就是他的计费模式:按需按量计费。在数据库存储层面,阿里云推出 Serverless 分布式数据库 Tablestore,和函数计算 FC 是最佳拍档。
1、前提
- 请先到 tablestore 控制台,开通服务
- 使用主账号创建按量付费的实例
- 在实例管理页面获取访问地址以及实例名
2、Initializer 函数
首先让我们先认识下 initializer 函数,initializer 函数能够保证统一实例成功并且仅成功执行一次。这个特性非常适合我们的数据库初始化连接。
const TableStore = require('tablestore'); let internal; // 先定义一个全局变量 exports.initializer = (context, callback) => try const endpoint = process.env.tablestore_endpoint; // tablestore的连接地址 const instanceName = process.env.tablestore_instanceName;// tablestore实例名 const tableClient = new TableStore.Client( accessKeyId: context.credentials.accessKeyId, accessKeySecret: context.credentials.accessKeySecret, stsToken: context.credentials.securityToken, endpoint, instancename: instanceName, ); internal = tableClient, TableStore ; callback(); catch (err) callback(err.message);
3、handler函数
数据库建立连接后,我们就可以在 handler 函数中处理业务逻辑。
const http = require('@serverless-devs/dk'); http // 创建表 .post("/table", async (ctx, next) => const tableName = ctx.request.body; const tableClient = ctx.req.requestContext.internal; const params = tableMeta: tableName, primaryKey: [ name: 'id', type: 'INTEGER', , ], , reservedThroughput: capacityUnit: read: 0, write: 0, , , tableOptions: timeToLive: -1, // 数据的过期时间, 单位秒, -1代表永不过期. 假如设置过期时间为一年, 即为 365 * 24 * 3600. maxVersions: 1, // 保存的最大版本数, 设置为1即代表每列上最多保存一个版本(保存最新的版本). , streamSpecification: enableStream: true, //开启Stream expirationTime: 24, //Stream的过期时间,单位是小时,最长为168,设置完以后不能修改 , ; await tableClient.createTable(params); ctx.body = success: true, message: `$tableName表已创建成功`, ) exports.handler = (req, res, context) => context.internal = internal; http()(req, res, context); ;
3、快速体验
1. Serverless Devs 提供 tablestore 组件, 通过一行命令快速体验
$ s init dk-tablestore
2. 本地调试
$ cd code $ npm install $ npm run serve
3. 一键部署到函数计算 FC
回到项目根目录(s.yaml平级),执行命令
$ s deploy
社区网址一览
- 社区官网
http://www.serverless-devs.com/
- 项目仓库
https://github.com/Serverless-Devs/Serverless-Devs
- Serverless Desktop 桌面客户端
https://serverlessdevs.resume.net.cn/zh-cn/desktop/index.html
- Serverless 应用开发者套件
http://serverless-dk.oss.devsapp.net/docs/tutorial-dk/intro/react
- Serverless Devs CLI
https://serverlessdevs.resume.net.cn/zh-cn/cli/index.html
- Serverless Hub 应用中心
https://serverlesshub.resume.net.cn/#/hubs/special-view
- 场景上手 Serverless Devs
点击链接(https://developer.aliyun.com/adc/expo/serverless),立刻参与场景体验!
原文链接:https://developer.aliyun.com/article/791586?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
serverlessdevs2.0全新发布,让serverless应用开发更简单
...ss开发者平台ServerlessDevs。历经近一年精心打磨,今天ServerlessDevs2.0正式版全新发布。ServerlessDevs2.0在平台能力、应用模板以及开发者套件方面能力提升,更加贴近开发者的实际生产诉求,使用体验再提升, 查看详情
serverlessdevs2.0全新发布,让serverless应用开发更简单
...ss开发者平台ServerlessDevs。历经近一年精心打磨,今天ServerlessDevs2.0正式版全新发布。ServerlessDevs2.0在平台能力、应用模板以及开发者套件方面能力提升,更加贴近开发者的实际生产诉求,使用体验再提升, 查看详情
serverlessdevs2.0全新发布,让serverless应用开发更简单(代码片段)
...ss开发者平台ServerlessDevs。历经近一年精心打磨,今天ServerlessDevs2.0正式版全新发布。ServerlessDevs2.0在平台能力、应用模板以及开发者套件方面能力提升,更加贴近开发者的实际生产诉求,使用体验再提升 查看详情
wsg-200e上网行为管理网关开箱测评
...机器背面采用双风扇散热,VGA接口可以接显示器调试。2.开箱,机箱里面 查看详情
涂鸦智能三明治音视频核心板(bk7256)开箱测评
bk7256是一颗高性能同时支持wifi6和蓝牙的芯片。使用32位双risv-v作为内核,最大时钟320M。集成音频adc/dac,cmos摄像头接口,16bitrgb显示屏、8080显示屏接口,支持硬件jpeg编解码。内置512K内存,8MPSRAM,4Mflash。... 查看详情
涂鸦智能三明治音视频核心板(bk7256)开箱测评
bk7256是一颗高性能同时支持wifi6和蓝牙的芯片。使用32位双risv-v作为内核,最大时钟320M。集成音频adc/dac,cmos摄像头接口,16bitrgb显示屏、8080显示屏接口,支持硬件jpeg编解码。内置512K内存,8MPSRAM,4Mflash。... 查看详情
colabpro+每月50刀的会员值不值?有人做了个开箱测评
...artinHenze的开发者最近充了ColabPro+会员,我们来看看ta的「开箱测评」。事情是这样的,MartinHenze参加了Kaggle的比赛,用的是自己的笔记本电脑,对于小模型和小图像来说自己的电脑也够用,但要想在排行榜上打榜升级,就必须扩... 查看详情
最新风控模型竞赛开始了!金融大数据应用-企业信贷风险防控-中国建设银行数据集-作者开箱测评
...大数据应用-企业信贷风险防控-中国建设银行数据集-作者开箱测评》各位朋友,最新金融风控模型竞赛开始了!竞赛名称为金融大数据应用:企业信贷风险防控;组织单位:数字中国建设峰会组委会;中国建设银行提供模型竞赛... 查看详情
涂鸦智能三明治音视频核心板(bk7256)开箱测评
bk7256是一颗高性能同时支持wifi6和蓝牙的芯片。使用32位双risv-v作为内核,最大时钟320M。集成音频adc/dac,cmos摄像头接口,16bitrgb显示屏、8080显示屏接口,支持硬件jpeg编解码。内置512K内存,8MPSRAM,4Mflash。... 查看详情
测评想买投影仪,预算又不多,该怎么选?——三款高性价比投影仪pk测评
...值的颜值狗,测评当然首先还是看颜值……2.1坚果H6开箱图场景图2.2腾讯极光T1开箱图场景图2.3联想T6X开箱图场景图外观方面,坚果的微果H6外观呈圆润的方正形,机身顶部采用了金属质感的上盖,并且机身四周采... 查看详情
游匣g15新机开箱测评,果然顶配是真香
关于游匣G15我要说的是,这台游戏本是直击心怀,无论是颜值,还是配置都符合我个人续期。今年新推出的机能绿,配上远征设计语言,光是看起来就很有气质,摸起来能感受到微微磨砂感,但是又不... 查看详情
测评西圣ava蓝牙耳机,一款轻便且极具性价比的真无线蓝牙耳机
...f1a;10天※外观设计※从西圣Ava这款蓝牙耳机的外包装以及开箱就可以看出,这是一款及其小巧和轻便的无线蓝牙耳机 查看详情
测评西圣ava蓝牙耳机,一款轻便且极具性价比的真无线蓝牙耳机
...f1a;10天※外观设计※从西圣Ava这款蓝牙耳机的外包装以及开箱就可以看出,这是一款及其小巧和轻便的无线蓝牙耳机 查看详情
测评西圣ava蓝牙耳机,一款轻便且极具性价比的真无线蓝牙耳机
...f1a;10天※外观设计※从西圣Ava这款蓝牙耳机的外包装以及开箱就可以看出,这是一款及其小巧和轻便的无线蓝牙耳机 查看详情
测评西圣ava蓝牙耳机,一款轻便且极具性价比的真无线蓝牙耳机
...f1a;10天※外观设计※从西圣Ava这款蓝牙耳机的外包装以及开箱就可以看出,这是一款及其小巧和轻便的无线蓝牙耳机,产品开箱清单包括耳机仓(包含一副耳机)、数据线和一份使用说明书。外表呈乳白色、圆润... 查看详情
pd.index(ser2).get_indexer(ser1),返回ser1中各元素在ser2中的索引位置(代码片段)
pd.Index(ser2).get_indexer(ser1),返回ser1中各元素在ser2中的索引位置 #pd.Index(ser2).get_indexer(ser1),返回ser1中各元素在ser2中的索引位置ser1=pd.Series([‘c‘,‘a‘,‘b‘,‘b‘,‘c‘,‘a‘])ser2=pd.Series([‘c‘,‘b‘,‘a‘])mask=pd.Index(ser2).get... 查看详情
ser.read() 有效,但 ser.readLine() 抛出错误
】ser.read()有效,但ser.readLine()抛出错误【英文标题】:ser.read()works,butser.readLine()throwserror【发布时间】:2018-01-1605:34:33【问题描述】:我正在尝试使用Python从Arduino读取串行值。>>>ser.read()\'2\'>>>a=ser.readLine()Traceback(most... 查看详情
等保二级需要测评吗?多久测评一次?
等保二级需要测评吗?多久测评一次?很多企业都存在这样的疑问,为此我们小编就给大家详细讲解一下。等保二级需要测评吗?多久测评一次?一般二级等保是需要每两年进行一次等保测评,特殊行业则... 查看详情