请教一下 Java 写物联网项目监控设备上下线方案

2023-12-08 14:53:32 +08:00
 yzqdm

刚入行不太懂。目前服务端用 springboot ,设备通讯协议是 mqtt ,然后 mqtt 服务器是用开源版的 EMQX 。然后现在有个问题,就是上一个人写的监控设备掉线是用定时任务来做的,就是隔一段时间查询数据库里的设备,哪些设备超过设定的时间没有更新状态,就认为掉线。但是这样做的问题就是隔一段时大批量更改设备状态,并且实时性不高。现在想的是哪个设备掉线了,mqtt 那边就推送这个设备掉线的信息到 java 程序中。我查了一下 mqtt 中有遗嘱功能,但是另一个技术说 EMQX 的遗嘱消息存在内存里的,进程挂了或者其他原因服务器重启了,这段时间的消息就没了,所以没用他里面的遗嘱功能。 想请教一下有这方面经验的大佬能提供一些建议。有没有别的方案可行,或者目前物联网公司的主流方案是怎么样的,谢谢

2703 次点击
所在节点    Java
24 条回复
NessajCN
2023-12-08 15:00:21 +08:00
心跳检测呗
ymz
2023-12-08 15:06:08 +08:00
设备有心跳包,但是心跳包如果网络波动,掉线也挺频繁

而且还有设备一直在线,但是不正常上报数据,这种你算在线,离线。
superychen
2023-12-08 15:13:19 +08:00
nealHuang
2023-12-08 15:13:50 +08:00
遗嘱+心跳。

收到遗嘱可以认为是下线,收到心跳后,也需要做超时检查,例如 10 秒一次心跳,做一个 60s 超时,60 秒内继续收到,就继续续心跳,否则认为离线。(这块可以参考 kafka 的时间轮算法,可以管理很多实例的心跳连接,性能很高。)

至于设备一直在线、但是不上报数据,也可以利用时间轮实现,可以加多一个 异常状态
MoYi123
2023-12-08 15:23:03 +08:00
broker 都重启了, 那设备不是全部离线? 连回来的时候再慢慢更新啊.
xuanbg
2023-12-08 15:50:31 +08:00
@ymz 一般都是连续多次没有检测到心跳才判定断线,哪有网络稍有波动就误报断线的
kuanat
2023-12-08 15:54:29 +08:00
我觉得这个事情是个工程问题而非技术问题。


“监控设备掉线是用定时任务来做的”:
说明设备本身就没有心跳机制,只有数据上报功能。工程上这个数据上报行为如果是固定间隔的就能当心跳来用,如果不是,那上面的判定逻辑是没问题的。
后者情况下,不管设备是不是真下线,超过一定时间没有数据上报都认为设备已经下线。对于判定在线的设备,你也只能说截至最后一条消息的时刻,该设备还在线。再换句话,判断是否在线这个事情不需要那么准确。


“隔一段时大批量更改设备状态,并且实时性不高”:
理论上监控系统的实时性不可能强于数据上报的最小间隔,只要定时任务周期和数据上报间隔保持一致就可以了。


“mqtt 那边就推送这个设备掉线的信息到 java 程序”:
主动轮训变事件监听,很标准的做法。技术上说,数据上报消息处理流程不仅写数据库,同时转发给 java 程序让它自己维护一份在线状态表就可以了。


“EMQX 的遗嘱消息存在内存”:
这个消息丢了很重要吗,进程重启很频繁吗?


以我的经验来说,物联网业务里对于单设备状态监控的实时性和准确性要求不高的,你能根据这个数据,给出判定“设备损坏”或者“区域网络失效”之类的经验参数才是真正的目的。这个事情可以容忍非常高的 false positive ,没有必要纠结微观细节。
xwayway
2023-12-08 16:42:04 +08:00
一般都是设备发送心跳包,比如说每 5s 发送一个心跳包,你可以根据实际情况设置连续 30s 没收到心跳,就认为设备下线了。当然判定方法具体怎么做又有很多种方案了
1. 收到心跳更新一下 db ,配合定时任务,更新 db 中设备在线状态。
2. 收到心跳包更新 redis key 过期时间,同时订阅 redis key 过期事件,根据事件修改设备在线状态,或者干脆就直接从 redis 取设备在线状态,就不用更新 db 了。
具体要怎么做,还是看你实际业务。
enjoyCoding
2023-12-08 17:10:52 +08:00
之前在物联网他们就是按照上报时间大一点点判断设备是否在线的, 10 分钟上报一次数据 那他大概 12~15 分钟没上报数据我们就认为他下线了. 我当时也觉得不好
1. 因为上报数据是动作, 是否在线是状态, 由动作推理状态并不合理
2. 至少设备少上报了一条数据才会知道设备离线, 无法提前预警
但是想不出更好的办法. 嵌入式也说了 发心跳包在规模小的时候更好, 但是比较耗电, 移动物联网真的没更好办法了吧....
yazinnnn0
2023-12-08 17:29:57 +08:00
emqx 有 webhook, 掉线可以发送特定 http 请求

https://www.emqx.io/docs/zh/latest/data-integration/webhook.html
litchinn
2023-12-08 17:34:15 +08:00
不是自带吗,https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
emqx 像楼上说的有在线离线主题呀
youknowiam
2023-12-08 17:42:35 +08:00
不如上 ThingBoard
qinfengge
2023-12-08 17:53:00 +08:00
我今天刚写了篇博客,用的 webhook 维护的上下线通知😎
https://blog.gggg.plus/java-shi-shi-xiao-xi-tui-song--er-
ChoateYao
2023-12-08 18:00:30 +08:00
这是业务问题,而不是技术问题,问你家的产品经理去。

如何定义设备掉线
andyxq
2023-12-08 19:25:18 +08:00
借下#8 @xwayway 的话:
一般都是设备发送心跳包,比如说每 5s 发送一个心跳包,你可以根据实际情况设置连续 30s 没收到心跳,就认为设备下线了。
一个高效一点的方案是:利用 redis 的 ZSet ,设备发送一包心跳后计算设备下次的离线时间(当前时间戳+30 秒), 写入到 ZSet 中 value 为设备 id 、score 为计算出的离线时间。(心跳计算和写入 redis 的操作要按批,不要一个一个搞)
另启动一个线程,定时每几秒试用 redis ZRANGEBYSCORE 命令获取 0 到当前时间戳的所有设备,这些设备就是要离线的设备。 然后你可以按照你的业务处理了
stinkytofu
2023-12-08 23:55:53 +08:00
楼上都没说到点子上,EMQX 系统事件中是有设备上下线的系统主题的, 你只要订阅这个主题就能收到上下线消息, 具体可以搜索一下, 使用很简单方便, 除了上下线还有其他系统事件都挺有用的
anjingdexiaocai
2023-12-09 07:57:16 +08:00
ws 连接,然后心跳检测,物联网主流是不是用 netty 呀
bthulu
2023-12-09 11:47:21 +08:00
用 zookeeper 啊, 所有设备都连到 zookeeper 上, 服务端订阅离线通知就行了
wildlife
2023-12-09 15:53:02 +08:00
设备影子
SANJI59
2023-12-11 09:37:52 +08:00
emqx 有规则规则引擎,直接 java 写个接口,配置到 emqx 规则引擎上就行。自己定义 sql 规则

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/998696

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX