介绍:如何使用serverless架构实现全双工通信的应用,serverless架构中如何使用数据库,本文为您揭晓答案|谢寒(阿里云云原生中间件前端总监)Serverless的概念是即时弹性,用完了就走。service不是long-running的,也就是说像websocket这种长连接请求方式似乎不太适合Serverless。有没有其他的方式既能满足长连接方式的要求,又能利用Serverless本身的特点呢?答案是肯定的。在上一篇文章中我们讲到了网关的关键作用,那么这次网关也是用来解决全双工通信的问题。本次我们就以弹幕场景为例,给大家展示一下我们是如何使用Serverless架构来实现这个场景的。应用效果预览弹幕应用的实际场景有很多,比如运营推广、年会活动等,但通常需要很长时间才能实现一套受控的流程并部署发布。这篇实战文章,让你在2分钟内部署好自己的弹幕应用。同时支持炫彩弹幕内容控制,你可以用它来丰富公司年会的形式。文末也会贴上源码,供大家参考和二次定制。架构概览整体架构还是采用dns解析->网关->oss|fc。不同的是分为三个静态资源项目,功能部分使用事件驱动和http结合,api部分使用tablestore进行数据持久化。流程描述弹幕应用主体工程包括大屏、个人用户、管理员三个客户端,以及一个注册设备的service&api服务。客户端和服务器之间的长连接由网关承载。每次客户端连接到网关时,网关都会存储设备号并触发注册功能,设备号会存储在tablestore中。当用户通过网关向api服务发起弹幕时,api服务会查询是否控制弹幕。如果没有控件,则直接搜索当前大屏设备id,下行调用网关。进入前端页面,展示数据。如果被控制,查询在线管理员的设备,并通知网关弹幕下行,网关发送到管理员前端页面。数据表设计装备(equipment)弹幕(bulletscreen)拦截器(filter)1.准备工作同上篇《人人都是 Serverless 架构师 | 现代化 Web 应用开发实战》。需要提前准备好域名,安装ServerlessDevs开发者工具,以及以下产品:云解析DNSAPI网关功能计算对象存储OSSTablestore这次我们介绍了tablestore的数据库内存数据的持久化功能,也是需要创建一个数据库实例进行备份。2、操作步骤为了更好的演示效果,本次演示使用ServerlessDesktop向大家展示如何在2分钟内部署一个复杂的弹幕应用。您可以根据自己的需要选择ServerlessDevsCli或者ServerlessDesktop来初始化、部署和构建弹幕应用。1)秘钥配置,请参考秘钥获取文档:http://www.serverless-devs.co...2)初始化除了将应用模板下载到本地,这个初始化也会帮助初始化tablestore和data的表,所以需要预先配置几个参数:secretkeyalias-对应你的阿里云账号domainname-自定义域名bucketName-ossbucketnameendpoint-对应tablestore的公网访问地址instance-对应tablestore的实例名配置参数写好后点击“确定”,接下来的工作就是调用ServerlessDevs,帮我们初始化弹幕应用的表。3)构建部署初始化完成后,我们重新进入配置页面部署项目。配置信息->全运行->部署点击后,剩下的交给ServerlessDevs,帮我们完成:播放器的大屏、管理后台和前端部署;部署注册功能和api功能,以及网关路由设置和绑定网关域名4)查看部署效果,查看网关功能计算OssDNS。这时候访问barrage.serverless-developer.com发现访问不一样了。原因是apigateway的域名和oss的域名没有绑定成功。手动处理吧:下到barragego.serverless-developer.com看看效果:2.数据库细节我想说说数据库。这次用的主数据库确实比较新,就是tablestore。1)数据库配置传递可以看到,我们在初始化应用的时候,填写了数据库的公网访问地址和实例名信息。初始化时,会将用户的输入配置写入s.yaml。这里,如果是建议从s.yaml中提取敏感信息放在.env环境中,忽略这个文件,减少数据库信息泄露到代码仓库的风险。最终,开发者会将这两个基本信息放入函数计算的环境变量中,然后各个运行时就可以通过环境变量获取这些值。比如这里是nodejs的运行环境,可以通过process.env.instance获取。除了实例名和公网访问地址外,数据库的初始化还需要用户的秘钥信息。鉴于秘钥信息的高敏感度,不建议直接在s.yaml中配置秘钥信息,而是通过给函数授权tablestore角色权限,让函数内置临时秘钥信息服务。函数服务授权配置如下:函数中获取的秘钥信息如下:2)数据库初始化为了减少数据库初始化次数,我们可以在函数的初始化方法中进行初始化。未释放功能时,无需重启connect,可直接使用数据库实例。这减少了请求响应时间。在单实例多并发的情况下比较实用。exports.initializer=(context,callback)=>{try{constak=context.credentials.accessKeyId;constsk=context.credentials.accessKeySecret;conststsToken=context.credentials.securityToken;SAT.init(endpoint,instance,ak,sk,stsToken);internal={tableClient:SAT,TableStore};打回来();}catch(err){回调(err.message);}}数据库实例初始化完成后,我们将其赋值给全局变量,在retrieve方法中获取实例,进行后续操作。3)CRUDtablestore的原生api对CRUD操作不够友好,tablestore社区提供了很好的封装SAT。我们用它来做基本的增删改查查询会很方便,代码看起来也很工整。//单主查询constgetInterceptor=async(ctx)=>{const{tableClient}=ctx.req.requestContext.internal;constres=awaittableClient.table('拦截器').get(1,cols=[]);returnres;}//查询全部constgetAllEquipment=async(tableClient,TableStore)=>{constres=awaittableClient.table('equipment').getRange(TableStore.INF_MIN,TableStore.INF_MAX,cols=[])returnObject.keys(res).map((key)=>res[key]);}//双主键(一个分区键,一个自增键)的插入constaddBarrage=async(ctx)=>{const{tableClient,TableStore}=ctx.req.requestContext.internal;const{fromId,fromName,color,fontSize='28px',checkStatus=0,message}=ctx.request.body;constcurrentTime=Date.now().toString();constnewData=Object.assign({},{fromId,fromName,color,fontSize,checkStatus:parseInt(checkStatus),message},{sendTime:currentTime,checkTime:currentTime});constres=awaittableClient.table('barrage',['gid','id']).put([1,TableStore.PK_AUTO_INCR],newData,c='I');returnres;}//更新constupdateBarrage=async(ctx)=>{const{tableClient}=ctx.req.requestContext.internal;const{checkStatus}=ctx.request.body;const{id}=ctx.request.params;constcurrentTime=Date.now().toString();constres=awaittableClient.table('barrage',['gid','id']).update([1,parseInt(id)],{checkStatus:parseInt(checkStatus),checkTime:currentTime},c='I')returnres;}//条件查询constgetBarrageByCondition=async(ctx)=>{const{tableClient,TableStore}=ctx.req.requestContext.internal;constres=awaittableClient.table('barrage').search('index',['checkStatus',0])returnres;}当然如果想做更高级的查询,需要查阅官网文件自己。总而言之,这个项目本身就是无服务器如何使用websockets的一个例子。你可以把它变成任何类似形式的应用,比如聊天室,多人协作平台等等。应用本身还有很大的改进空间,比如增加点赞的效果,增加管理员登录并注册到控制部分。总之,您可以根据自己的需要定制更高级的功能,相关源码已提供给您参考。下一章我会继续讲serverless和low-code的场景,分享一下我们最近做的一个实践。原文链接本文为阿里云原创内容,未经许可不得转载。
