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

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

  •  
  •   yzqdm · 352 天前 · 2653 次点击
    这是一个创建于 352 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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


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


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


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


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


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

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

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