人人都是 Serverless 架构师 | 弹幕应用开发实战

作者 | 寒斜(阿里云云原生中间件前端负责人)
如何使用 Serverless 架构实现全双工通信的应用,Serverless 架构中数据库是如何使用的,本篇文章将为您揭开答案。
Serverless 的理念是即时弹性,用完即走。服务并非长时间运行,这也就意味着像 websocket 这种长链接的请求模式看起来并不适合 Serverless。
是否有其它的办法即可以满足长连接模式请求,又能够利用 Serverless 本身特性呢?
答案是肯定的,上一篇文章我们谈及了网关的关键作用,所以这次也是通过网关来解决全双工通信的问题。本次将以弹幕场景为例,为大家展开我们是怎么使用 Serverless 架构来实现这个场景的。

应用效果预览
弹幕应用的实用场景比较多,比如运营推广,年会活动等。但是通常实现一套带管控的流程,且部署发布的话,一般会花费比较长的时间。本篇实战则可以让你在 2 分钟之内就部署好自己的弹幕应用。同时做到支持炫彩和弹幕内容管控,你可以用它来丰富公司年会的形式。文末也会贴上源码,可以供大家参考和二次定制。

架构一览
整体架构依然采用 dns 解析 -> 网关 -> oss | fc 。不一样的是分了 3 个静态资源的工程,函数部分则采用事件驱动和 http 相结合,并且 api 部分采用 tablestore 进行数据的持久化。

流程说明
弹幕应用总工由大屏幕, 个人用户,管理员三个客户端,以及一个注册设备的服务 & api 服务组成。客户端跟服务端的长链接由网关来承载,每次客户端连接到网关的时候,网关都会存储设备编号,并且触发一次注册函数,设备编号存储到 tablestore。
当用户发起弹幕的时候经网关到 api 服务,api 服务会做一次查询先判断弹幕是否被管制,如果无管制则直接查找当前的大屏幕设备 id,并且进行网关的下行调用,网关在发到前端页面,显示数据。如果被管制,则查询在线的管理员设备,将弹幕下行通知到网关,网关发送给管理员前端页面。
数据表设计
- equipment(设备)
| 字段 | 类型
| 说明 |
| --- | --- | --- |
| id
| string
| 设备表主键
|
| deviceld
| string | 设备id |
| docld
| string | 备用字段
|
| type
| string | 设备类型(screen | admin)
|
barrage(弹幕)
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| gid | string | 分区键 |
| id | integer | 主键自增 |
| fromId | string | 弹幕作者id |
| fromName | string | 来源作者名称 |
| color | string | 弹幕颜色 |
| fontSize | string | 弹幕字体大小 |
| checkStatus | integer | 弹幕状态0(未处理)1(审批通过)2(审批未过) |
| sendTime | string | 弹幕发送时间 |
| checkTime | string | 弹幕更新时间 |
| message | string | 弹幕内容 |interceptor (过滤器)
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | integer | 主键/分区键 |
| status | integer | 拦截状态0不拦截 1拦截 2拦截加过滤 |
| filterWords | string | 过滤字段 |
1、准备工作
同前篇《人人都是 Serverless 架构师 | 现代化 Web 应用开发实战》文章一样需要提前准备好域名,并安装好 Serverless Devs 开发者工具,以及下面的产品:
- 云解析 DNS
- API 网关
- 函数计算
- 对象存储 OSS
- Tablestore
这次我们引入了 tablestore 的数据库记性数据的持久化功能,同样需要创建好数据库实例备用。
2、操作步骤
为了更好的展示效果,本次演示使用 ServerlessDesktop 来给大家演示一下如何 2 分钟部署一个复杂的弹幕应用。你可以根据自身需要选择 Serverless Devs Cli 或者 Serverless Desktop 对弹幕应用进行初始化和部署构建。
1)秘钥配置
可参考密钥获取文档:
http://www.serverless-devs.com/zh-cn/docs/provider-config/alibabacloud.html
2)初始化

本次初始化除了需要将应用模板下载到本地之外,还会帮忙初始化 tablestore 的表和数据,因此需要预配置几个参数:
- 秘钥别名 - 对应你的阿里云账号
- 域名 - 自定义域名
- bucketName - oss 的 bucket 名称
- endpoint - 对应 tablestore 实例的公网访问地址
- instance - 对应 tablestore 的实例名
预配置参数写好后点击 “确定”,接下来的工作就叫给 Serverless Devs,它会帮我们初始化弹幕应用的表。
3)构建部署
初始化之后,我们重新进入配置页面,对项目进行部署。配置信息 -> 全量操作 -> deploy 点击后其他的就交给 Serverless Devs了,它会帮助我们完成:
- 大屏幕,管理后台和玩家的前端部署;
- 注册函数以及 api 函数的部署
- 以及网关的路由设置和网关的域名绑定
4) 部署效果查看
- 网关

- 函数计算

- Oss

- DNS

此时访问_ barragego.serverless-developer.com _发现访问不同,检查发现原因是 apigateway 的域名和 oss 域名都未绑定成功,我们手动处理一下:


接下来再访问 barragego.serverless-developer.com 即可看到效果:
2、数据库明细
数据库方面想拿出来说一下,主要本次用的数据库确实比较新,也就是 tablestore。
1)数据库配置传递
可以看到,我们在初始化应用的时候是填写了数据库的公网访问地址和实例名称信息的,初始化的时候会把用户的输入配置写入到 s.yaml 中,这里如果是比较敏感的信息建议从 s.yaml 提取出来放到 .env 环境中,并且 ignore 掉这个文件,减少数据库信息被泄露到代码仓库的风险。
最终 Devs 会把这两个基本信息放到函数计算的环境变量中然后各运行时可以通过环境变量取到这些值,比如这里是 nodejs 的运行环境,则通过 process.env.instance 获取。
除了实例名称和公网访问地址外数据库的初始化还需要 用户的秘钥信息。鉴于秘钥信息的敏感性比较高,不建议直接把秘钥信息配置到 s.yaml 里,而是通过给函数服务授权 tablestore 角色权限,让函数内置临时秘钥信息。
- 函数服务授权配置如下:

- 函数内获取秘钥信息如下:

2)数据库初始化
为了减少数据库初始化次数,我们可以在函数的 initializer 方法中初始化,当函数未被释放的时候可以直接使用数据库的实例而不必重新连接。这样可以降低请求响应时间。单实例多并发的情况下比较实用。
exports.initializer = (context, callback) => {
try {
const ak = context.credentials.accessKeyId;
const sk = context.credentials.accessKeySecret;
const stsToken = context.credentials.securityToken;
SAT.init(endpoint, instance, ak, sk, stsToken);
internal = { tableClient: SAT, TableStore };
callback();
} catch (err) {
callback(err.message);
}
}
数据库实例初始化之后,我们通过赋值给全局变量来从其他的方法中取得实例,进行后续的操作。
3)CRUD
tablestore 原生的 api 去做 CRUD 操作用户体验不够友好,tablestore 社区提供了一个很好的封装 SAT。我们用它来做基础的增删改查会非常的方便,代码看起来也非常整洁。
// 单主键查询
const getInterceptor = async (ctx) => {
const { tableClient } = ctx.req.requestContext.internal;
const res = await tableClient.table('interceptor').get(1, cols = []);
return res;
}
// 查询全部
const getAllEquipment = async (tableClient,TableStore) => {
const res = await tableClient.table('equipment').getRange(TableStore.INF_MIN, TableStore.INF_MAX, cols = [])
return Object.keys(res).map((key)=> res[key]);
}
// 双主键(一个分区键,一个自增键)的插入
const addBarrage = async (ctx) => {
const { tableClient, TableStore } = ctx.req.requestContext.internal;
const { fromId, fromName, color, fontSize = '28px', checkStatus = 0, message } = ctx.request.body;
const currentTime = Date.now().toString();
const newData = Object.assign({}, { fromId, fromName, color, fontSize, checkStatus: parseInt(checkStatus), message }, { sendTime: currentTime, checkTime: currentTime });
const res = await tableClient.table('barrage', ['gid', 'id']).put([1, TableStore.PK_AUTO_INCR], newData, c = 'I');
return res;
}
// 更新
const updateBarrage = async (ctx) => {
const { tableClient } = ctx.req.requestContext.internal;
const { checkStatus } = ctx.request.body;
const { id } = ctx.request.params;
const currentTime = Date.now().toString();
const res = await tableClient.table('barrage', ['gid', 'id']).update([1, parseInt(id)], { checkStatus: parseInt(checkStatus), checkTime: currentTime }, c = 'I')
return res;
}
// 条件查询
const getBarrageByCondition = async (ctx) => {
const { tableClient, TableStore } = ctx.req.requestContext.internal;
const res = await tableClient.table('barrage').search('index', ['checkStatus', 0])
return res;
}
当然如果你想做更高级的查询,就需要自己去查阅官网文档了
总结
这个项目本身是对 Serverless 如何使用 websocket 的一个展示示例。你可以把它变成任意相近形态的应用,比如聊天室,多人协作平台等。
应用本身也还有很多改进空间,比如增加点赞效果,管控部分可以加上管理员的登录注册等。总之你可以根据自身需求定制更高级的功能,相关的源码已经提供出来供大家参考。下个篇章我会继续跟大家聊一聊 Serverless 和低代码的场景,并分享一个我们最近做的实践。
文中涉及网址汇总:
Serverless Devs:https://github.com/Serverless-Devs
云解析DNS:https://wanwang.aliyun.com/domain/dns
API网关:https://www.aliyun.com/product/apigateway
函数计算:https://www.aliyun.com/product/fc
对象存储OSS:https://www.aliyun.com/product/oss
ServerlessDesktop:http://www.serverless-devs.com/zh-cn/desktop/index.html
Serverless Devs Cli:http://www.serverless-devs.com/zh-cn/cli/index.html
Serverless Hub:https://serverlesshub.resume.net.cn/#/hubs/specialview
Tablestore表格存储:https://www.aliyun.com/product/ots
官网文档:https://help.aliyun.com/document_detail/27304.html?spm=5176.54465.J_7985555940.4.15942e0c3qkHbU
源码:https://github.com/devsapp/start-barrage
更多内容关注 Serverless 微信公众号(ID:serverlessdevs),汇集 Serverless 技术最全内容,定期举办 Serverless 活动、直播,用户最佳实践。
人人都是 Serverless 架构师 | 弹幕应用开发实战的更多相关文章
- 诚聘.NET架构师、高级开发工程师(2019年8月29日发布)
招聘单位是ABP架构设计交流群(134710707)群主阳铭所在的公司 公司简介 七二四科技有限公司成立于2015年,成立之初便由金茂资本按估值2亿投资2200万,进行“健康724”平台搭建,2017 ...
- 葡萄城首席架构师:前端开发与Web表格控件技术解读
讲师:Issam Elbaytam,葡萄城集团全球首席架构师(Chief Software Architect of GrapeCity Global).曾任 Data Dynamics.Inc 创始 ...
- 空中网招聘Java架构师、数据库开发等各类人才
爱好网络游戏吗?爱好网站开发技术吗? 有没有想过可以成为史诗级MMO RPG<激战2>运营团队中的一员? 如果下面的职位有合适你的,加入我们吧! http://gw2.kongzhong. ...
- 阿里云云开发平台助力风变科技Serverless架构升级实战
阿里云云开发平台助力风变科技Serverless架构升级实战 背景 风变科技 一个希望通过技术去推动下一代基础教育的组织.旗下产品包括第一代的熊猫书院(读书类产品).第二代的熊猫小课(泛学科综合学习平 ...
- 2010“架构师接龙”问答--杨卫华VS赵劼(转)
add by zhj:虽然是几年前的文章,但还是很有参考价值的 原文:http://blog.zhaojie.me/2010/05/programmer-magazine-2010-5-archite ...
- 程序员、架构师、技术总监、CTO
程序员 程序员,英文名coder/programmer,大家常自嘲叫码农的阶段.这个角色职责是把需求或产品实现为用户可用的软件产品. 此职位为执行级别.另外因为经验较少,一般需要求助别人,或与别人一起 ...
- IT架构师介绍-软件架构设计学习第一天(非原创)
文章大纲 一.架构师定义二.架构师分类与具备能力三.研发人员发展的技术路线四.架构师知识体系五.参考文章 一.架构师定义 什么是架构师,这个聊架构话题时永恒的问题.每个公司对架构师的定位也有所 ...
- 好好讲一讲,到底什么是Java高级架构师!
一. 什么是架构师 曾经有这么个段子: 甲:我已经应聘到一家中型软件公司了,今天上班的时候,全公司的人都来欢迎我. 乙:羡慕ing,都什么人来了? 甲:CEO.COO.CTO.All of 程序员,还 ...
- 如何从普通程序员晋升为架构师 面向过程编程OP和面向编程OO
引言 计算机科学是一门应用科学,它的知识体系是典型的倒三角结构,所用的基础知识并不多,只是随着应用领域和方向的不同,产生了很多的分支,所以说编程并不是一件很困难的事情,一个高中生经过特定的训练就可以做 ...
- 架构之:serverless架构
目录 简介 什么是serverless serverless的例子 简单的三层服务 消息驱动 FaaS FaaS的缺点 FaaS的优点 总结 简介 不知道什么时候,出现了一个叫做Serverless架 ...
随机推荐
- 【译】使用 GitHub Copilot 编写 Git 提交
在花费数小时修复 bug 或更新特性之后,我们开发人员最不愿意做的事情往往是仔细说明 Git 提交的内容.最新的 Visual Studio 预览版可以帮到您.使用新的生成 Git 提交消息特性来帮助 ...
- 向“创新者”升阶,程序员当下如何应对 AI 的挑战
随着 AI 技术的飞速发展,特别是大模型的出现,传统的程序员角色正在经历深刻的变革,我们不得不重新对自己进行审视和思考. 通用领域大模型的"泛化能力" 在过去的二十年内,AI 领域 ...
- 快速认识,前端必学编程语言:JavaScript
JavaScript是构建Web应用必学的一门编程语言,也是最受开发者欢迎的热门语言之一.所以,如果您还不知道JavaScript的用处.特点的话,赶紧补充一下这块基础知识. JavaScript 是 ...
- 技术Leader:像李云龙一样打造学习型团队
今天跟大家分享一下怎么样构建一个学习型的团队. 首先对于计算机行业而言,不明而喻,我们要接受的东西真的太多了.我们接触的信息和变化也太多了.如果只是因循守旧,排斥新东西,那么我们被时代淘汰只是个时间问 ...
- Java如何连接Mysql数据库
条件:eclipse.MySQL .jdbc驱动 eclipse.MySQL 的安装.下载jdbc连接驱动 eclipse的安装去官网下载并安装 MySQL .jdbc的下载地址请访问:https:/ ...
- python 图片相关
python 图片相关 本篇介绍两种方式来打开图片. 1: 使用matplotlib #!/usr/bin/python3 # -*- coding: UTF-8 -*- ""&q ...
- 牛客网刷Java记录第一天
第一题 下列程序输出啥? public class StringDemo{ private static final String MESSAGE="taobao"; public ...
- ASR项目实战-任务队列在文件转写特性中的应用
转写时长超出60秒的语音文件,业界的竞品通常会使用创建异步转写任务的方式来提供支持. 一个简单.直接的实现方案,即: 网关服务接收到来自客户的转写请求时,将任务信息持久化至任务队列中. 由算法服务的实 ...
- Pikachu漏洞靶场 敏感信息泄露
敏感信息泄露 概述 由于后台人员的疏忽或者不当的设计,导致不应该被前端用户看到的数据被轻易的访问到. 比如: 通过访问url下的目录,可以直接列出目录下的文件列表; 输入错误的url参数后报错信息里面 ...
- Caffeine Cache缓存
SpringBoot 集成 Caffeine Caffeine 和 Spring Cache 依赖,使用注解方法实现缓存 依赖 <!--提供 Spring Boot 中的缓存支持--> & ...