V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yzqdm
V2EX  ›  Java

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

  •  
  •   yzqdm · 2023-12-08 14:53:32 +08:00 · 2714 次点击
    这是一个创建于 380 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    24 条回复    2023-12-18 18:41:29 +08:00
    NessajCN
        1
    NessajCN  
       2023-12-08 15:00:21 +08:00
    心跳检测呗
    ymz
        2
    ymz  
       2023-12-08 15:06:08 +08:00
    设备有心跳包,但是心跳包如果网络波动,掉线也挺频繁

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

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

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


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


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


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


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


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

    https://www.emqx.io/docs/zh/latest/data-integration/webhook.html
    litchinn
        11
    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
        12
    youknowiam  
       2023-12-08 17:42:35 +08:00
    不如上 ThingBoard
    qinfengge
        13
    qinfengge  
       2023-12-08 17:53:00 +08:00
    我今天刚写了篇博客,用的 webhook 维护的上下线通知😎
    https://blog.gggg.plus/java-shi-shi-xiao-xi-tui-song--er-
    ChoateYao
        14
    ChoateYao  
       2023-12-08 18:00:30 +08:00
    这是业务问题,而不是技术问题,问你家的产品经理去。

    如何定义设备掉线
    andyxq
        15
    andyxq  
       2023-12-08 19:25:18 +08:00   ❤️ 1
    借下#8 @xwayway 的话:
    一般都是设备发送心跳包,比如说每 5s 发送一个心跳包,你可以根据实际情况设置连续 30s 没收到心跳,就认为设备下线了。
    一个高效一点的方案是:利用 redis 的 ZSet ,设备发送一包心跳后计算设备下次的离线时间(当前时间戳+30 秒), 写入到 ZSet 中 value 为设备 id 、score 为计算出的离线时间。(心跳计算和写入 redis 的操作要按批,不要一个一个搞)
    另启动一个线程,定时每几秒试用 redis ZRANGEBYSCORE 命令获取 0 到当前时间戳的所有设备,这些设备就是要离线的设备。 然后你可以按照你的业务处理了
    stinkytofu
        16
    stinkytofu  
       2023-12-08 23:55:53 +08:00
    楼上都没说到点子上,EMQX 系统事件中是有设备上下线的系统主题的, 你只要订阅这个主题就能收到上下线消息, 具体可以搜索一下, 使用很简单方便, 除了上下线还有其他系统事件都挺有用的
    anjingdexiaocai
        17
    anjingdexiaocai  
       2023-12-09 07:57:16 +08:00 via Android
    ws 连接,然后心跳检测,物联网主流是不是用 netty 呀
    bthulu
        18
    bthulu  
       2023-12-09 11:47:21 +08:00
    用 zookeeper 啊, 所有设备都连到 zookeeper 上, 服务端订阅离线通知就行了
    wildlife
        19
    wildlife  
       2023-12-09 15:53:02 +08:00
    设备影子
    SANJI59
        20
    SANJI59  
       2023-12-11 09:37:52 +08:00
    emqx 有规则规则引擎,直接 java 写个接口,配置到 emqx 规则引擎上就行。自己定义 sql 规则
    yzqdm
        21
    yzqdm  
    OP
       2023-12-11 09:42:34 +08:00
    感谢大家的解答,决定试试 EMQX 里面上下线主题试试
    nealHuang
        22
    nealHuang  
       2023-12-11 11:47:04 +08:00
    emqx 的上下线主题会导致所有设备跟 emqx 强绑定,如果哪天某一台设备连接的 mqtt broker 不是 emqx ,你这台设备就没法监测了。
    ymz
        23
    ymz  
       2023-12-14 09:14:37 +08:00
    @andyxq 是否在离线放到 redis ,页面根据在离线分页查的时候就没法搞了
    andyxq
        24
    andyxq  
       2023-12-18 18:41:29 +08:00
    @ymz 这个只是接入层维护在线状态的一种方案,上层业务按在线状态筛选那可以往数据库同步一下状态。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2785 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:43 · PVG 19:43 · LAX 03:43 · JFK 06:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.