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

152 天前
 yzqdm

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

2142 次点击
所在节点    Java
24 条回复
NessajCN
152 天前
心跳检测呗
ymz
152 天前
设备有心跳包,但是心跳包如果网络波动,掉线也挺频繁

而且还有设备一直在线,但是不正常上报数据,这种你算在线,离线。
superychen
152 天前
nealHuang
152 天前
遗嘱+心跳。

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

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


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


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


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


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


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

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

如何定义设备掉线
andyxq
152 天前
借下#8 @xwayway 的话:
一般都是设备发送心跳包,比如说每 5s 发送一个心跳包,你可以根据实际情况设置连续 30s 没收到心跳,就认为设备下线了。
一个高效一点的方案是:利用 redis 的 ZSet ,设备发送一包心跳后计算设备下次的离线时间(当前时间戳+30 秒), 写入到 ZSet 中 value 为设备 id 、score 为计算出的离线时间。(心跳计算和写入 redis 的操作要按批,不要一个一个搞)
另启动一个线程,定时每几秒试用 redis ZRANGEBYSCORE 命令获取 0 到当前时间戳的所有设备,这些设备就是要离线的设备。 然后你可以按照你的业务处理了
stinkytofu
152 天前
楼上都没说到点子上,EMQX 系统事件中是有设备上下线的系统主题的, 你只要订阅这个主题就能收到上下线消息, 具体可以搜索一下, 使用很简单方便, 除了上下线还有其他系统事件都挺有用的
anjingdexiaocai
152 天前
ws 连接,然后心跳检测,物联网主流是不是用 netty 呀
bthulu
151 天前
用 zookeeper 啊, 所有设备都连到 zookeeper 上, 服务端订阅离线通知就行了
wildlife
151 天前
设备影子
SANJI59
150 天前
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