设备中心项目
为防止颅内退化,自己做过的事被遗忘;
将自己做过的项目经验记录下来变得非常有必要,本篇将记录的是,云平台,设备中心的项目经验
首先从项目的技术说起,和主流互联网项目技术一致,springboot一套,redis缓存,数据库mysql,mongdb。
技术
纯后台中心应用,使用了目前互联网主流体系的技术与框架
开发框架: SpringBoot一套
、MyBatis-plus
、easy-rule
、Dubbo
中间件:redis
、mqtt
、rabbitmq
、kaffka
、nacos
、XXL-JOB
数据库:Mysql
、Mongdb
、InfluxDB
工具:极光推送
、阿里云OSS
、阿里云短信
这是什么
设备中心,顾名思义,聚合设备的中心。
由三部分组成:
- 设备管理
- 设备网关
- 设备连接桶
设备管理: 包括但不限于设备的基本信息管理,设备消息的发送上游、设备远程云端功能的实现、设备登录、创建、烧录等操作的入口等等
设备网关:包括但不限于设备连接设备中心的中驱,设备消息的接收上游与实际发送消息者,设备消息的处理与分发、设备权限与路由的分配管理等等
设备连接桶:设备与设备中心进行业务级连接的地方
用白话文解释设备中心存在 的意义:
设备通过设备连接桶,登记自己的连接信息并且拿到对应的设备中心网关地址;
连接成功后,将自己的功能运行状态或者当前的属性状态\属性状态的变更,下发给设备网关,网关通过路由的负载均衡分配给设备中心。
设备中心将记录设备上报的属性状态,并且更新这台设备在设备中心的快照模型。
功能的运行,比如设备开、关、改变模式、属性变更等等,通过规则引擎下发给该设备配置的对应应用
有什么用
设备成功接入到设备中心之后,用户可以通过设备中心进行如下操作:
- 操作设备
- 获得设备当前信息和属性
- 同步设备
- 为设备进行云端功能赋值,比如云呼叫、云视听、OTA升级、设备配对等等...
- 设备黑名单,功能权限,信息修改等等管理功能
- 智能语音云平台、产商云平台等等云对云协议的接入
- ...
操作设备,获取信息等基础功能不说,拿云端功能赋值说说:
假设一台设备A,在生产的设计中只有开关功能。
生产之后客户想要一个语音对讲的功能如何实现?
按照正常的流程,需要将设备重新设计,进行硬件级的开发。
但是假如公司有云平台-设备中心的存在,为一个设备赋予语音对讲的功能就变的很简单了:
- 在设备中添加语音对讲标准模型的硬件
- 连接网络,接入设备中心
- 下载我司有语音对讲功能的APP,配对设备,使用其功能
这就是直接可以以最低成本为一个设备进行功能上的额外赋能
除此之外,设备端也可以通过接入设备中心用来为后续的功能扩展、软件升级、信息修改等云端远程功能预留入口
并且作为设备中心,是所有设备发送消息与接收消息的中轴。
以此为中心,可以通过mq转发的形式向下拓展无数个子级应用
怎么做的
设备连接通过与设备中心拟定的协议,通过mqtt建立长连接;
建立连接的过程类似用户登录,流程如下:
- 从连接桶拿到网关的请求地址和授权token
- 连接网关,通过授权码获得唯一登录的设备id和登录token
- 后续发送消息通过设备id+登录token鉴权
设备登录后就可以与设备中心进行请求-响应的消息交互;
消息交互流程如下:
- 开启线程池,拒绝策略为抛弃任务
- 根据约定好的协议,解析设备消息体
- 构建责任链的头链,并且开启链路,链路目前有如下:
- 异常消息体处理
- 响应消息处理
- 请求消息处理
- 限流处理
- 设备消息处理
- 设备消息处理为核心处理器,在这里将消息给到了消息解析器进行操作。
- 消息下发给规则引擎,通过mq转发给子级应用
技术难点
数据模型
设备会将自身的所有属性上报给设备中心,并且这个动作非常非常频繁。
比方说传感器,每秒上报自己的传感数据。
因此如果需要做到设备快照数据的时效性,就必须去考虑缓存设计以及部分更新的原则;
先判断读多还是写多,然后再思考数据一致性的强度,最后综合考虑性能成本;
数据存redis中,存redis的问题是属性进行修改时耗费很大,需要使用lua脚本而且是针对整个模型。假如模型数据过多,会很慢。
但是使用redis的原因也很明显,读取性能更高。
数据存mongdb中,基于文档型存储的方式保存性能更高,但是频繁读取性能弱于redis
因此会将设备的上报种类分为369等,经常读的会存在redis中,读的少的则会使用模型文件冷处理,生成文档对象存储在mongdb中。
针对数据一致性问题,分两种情况。
一是查询设备中心的设备数据,二是消费设备中心mq转发过来的设备数据。
比方说设备得上下线状态,在设备中心中,因为设备消息通过线程,队列,更新缓存原因会出现短时间内在线状态不一致的问题。
而通过消息中心转发的设备数据,则可能因为消息堆积,消费速率等影响,影响数据的实效性。
因此数据一致性,不单单只是缓存与数据库中内容一致性问题;还有应用APP上看到的和设备上展示的数据一致的问题;
前者考虑到的是最终一致性,可以接收短时间内数据库数据不一致,但是模型缓存一定会最先更新。
后者则是需要平衡整个链路的时间,从拿到设备中心转发过来的数据到具体使用的业务时间
设备数据存储
除了设备的数据模型外,设备中心还会记录一项非常重要的数据:设备日志
包括但不限于:上下线记录,上报数据记录,交互记录等等
最初考量一个数据库Mysql是能吞下,但是随着设备量的增大,表数据不可控的提升,最终会出现什么情况是可以预见的;
讨论的方案有两种:
- 水平,垂直分表,依然使用Mysql存储
- 数据库分摊压力,采用InfluxDB记录日志型数据
后者更适合此数据的存储场景
不同地区连接当地设备中心
cdn
设备中心本地化部署
边缘网关的设计
转发规则引擎
规则引擎使用
本地测试问题
因为设备不能像网页测试那样自由的进行环境切换,因此在烧录注册到设备中心的时候,一般使用的是设备中心测试环境,
国内外设备中心数据同步
项目实际生产Bug
nginx占用长连接
有一批设备,提供给的连接地址是通过nginx转发后的路由;
nginx针对http连接的处理是,转发结束就断开。
但是设备占用通过nginx去连接mqtt占用的是一个http长连接,而http长连接会在服务器上固定一个port;且nginx对此连接数有限制, 默认为2000.
所以通过时间推移,数据量变大,恰好并发产生将nginxhttp连接全部占满;
解决方式很简单,直接使用域名映射,不适用nginx
同时间戳重复消息
有一段时间,设备反应设备中心响应混乱,比方说设备一条发送请求,收到了多条响应请求,并且响应的报文是一样的;
线程池不够用
有一批设备的OTA升级流程会存在多次请求-响应的交互过程,因为设备对ota业务的调整会导致业务中时间过长;
由于是批量,并且一个设备是单独占据一个消息线程的。
在测试中,因为设备与设备中心都是在内网或者外网较近的环境下,因此每一天消息都会处理很快。
但是当设备迁移到偏远地区,比如国外服务器部署在德国,设备在俄罗斯,会存在毫秒级的网络阻塞问题;
最终定时任务+消息线程+规则引擎,将线程池直接占满。
导致这批设备批量进行ota升级时,有几台会进入重试状态;
解决:
虽然设备功能依然会因为重试机制正常运行,但是对调试人员来说体验很不好。
最终优化是:线程池不够,在大小不能扩容的前提下,进行跨线程的扩容。即设置一个项目体积非常小的mini设备中心,仅分担需要用到线程池进行简单交互:
比如mq转发、设备交互、回执等等的动作;