阿里云-物联网平台遇到的心跳问题小结

现象描述

使用物联网平台时,阿里的AMQP服务短时间内(1毫秒)向服务端推送了两条心跳信息,一条上线,一条下线。

调查逻辑

第一次关机重启
操作时间:2024-05-10 13:42:34
结果:阿里推给服务端两条数据
第一条:{“lastTime”:“2024-05-10 13:42:34.579”,“status”:“offline”}
第二条:{“lastTime”:“2024-05-10 13:42:34.580”,“status”:“online”}
服务端接收到数据的顺序为:
第一条:{“lastTime”:“2024-05-10 13:42:34.579”,“status”:“offline”}
第二条:{“lastTime”:“2024-05-10 13:42:34.580”,“status”:“online”}

第二次关机重启
目前状态:设备在线(因为服务端从阿里接收到的最后心跳数据为:{“lastTime”:“2024-05-10 13:42:34.580”,“status”:“online”})
操作时间:2024-05-10 13:44:36
结果:阿里推给服务端两条数据
第一条:{“lastTime”:“2024-05-10 13:44:36.811”,“status”:“offline”}
第二条:{“lastTime”:“2024-05-10 13:44:36.812”,“status”:“online”}
服务端接收到数据的顺序为:
第一条:{“lastTime”:“2024-05-10 13:44:36.812”,“status”:“online”}
第二条:{“lastTime”:“2024-05-10 13:44:36.811”,“status”:“offline”}

第三次关机不重启
目前状态:设备离线(因为服务端从阿里接收到的最后心跳数据为:{“lastTime”:“2024-05-10 13:44:36.811”,“status”:“offline”})
操作时间:2024-05-10 13:46:13
结果:从关机到2024-05-10 14:00:30 之间,阿里未推送心跳数据给服务端(中间间隔了差不多15分钟)
最后在2024-05-10 14:00:30阿里向服务端推送了设备离线数据
{“lastTime”:“2024-05-10 14:00:30.231”,“status”:“offline”}

第四次直接开机
目前状态:设备离线(因为服务端从阿里接收到的最后心跳数据为:{“lastTime”:“2024-05-10 14:00:30.231”,“status”:“offline”})
操作时间:2024-05-10 14:05:00
结果:阿里推给服务端一条数据
第一条:{“lastTime”:“2024-05-10 14:05:53.715”,“status”:“online”}
服务端接收到数据的顺序为:
第一条:{“lastTime”:“2024-05-10 14:05:53.715”,“status”:“online”}

这时发现阿里只推送了一条心跳数据过来,基于这个现象,做出一下猜测:
猜测:是否是关机重启间隔太短,导致阿里未及时推送离线数据,而造成在开机时阿里连续推送离线,在线两条心跳数据。
实施:可以做以下测试,进一步验证该猜测

测试用例1:基于当前状态,关机重启
测试用例2:关机不重启,等待5分钟,重新开机
测试用例3:关机不重启,等待15分钟,重新开机

阿里售后回复

针对该错误码的分析如下:

【错误码】427
【含义】设备下线异常。
【原因】设备证书信息被其他设备使用,使设备被迫下线。物联网平台仅以设备证书信息(productKey、deviceName、deviceSecret)来判断设备。

【排查】
1、核实一下三元组信息有没有多台设备在使用,可以新建一个三元组测试一下,排除这种情况
2、排查一下网络环境是否稳定
(1)控制台->设备详情->延迟测试
(2)设备端ping一下服务器地址,看看网络延迟
(3)自行通过网络诊断工具,诊断设备所处的网络环境
(4)让您们的协议栈工程师分析一下设备硬件的TCP/IP协议栈是否有问题。

【备注】
这种现象也称为: Kicked by the same device,设备互踢。

  1. 设备和物联网平台的连接是基于mqtt协议的,假设设置的心跳时间是300s,那么只有超过心跳时间后,平台还没有收到设备端发送的心跳包,才认为设备离线。如果在300s内,网络恢复,您的设备重新上线(也就是说设备本来离线,平台这边还是认为在线的,因为没有到300s),那平台就认为被同一台设备挤下线了,所以显示kicked by the same device。(设备端网络或电源不稳定,发生了瞬间断网或断电重连。这种情况下,设备与物联网平台是连接的,不影响设备使用。)

  2. 同一组三元组信息两个或以上设备同一时间连接,这个连接被踢掉了。

推测结论

设备开机登录了MQTT,此时强制关机重启设备,导致前一次登录没有下线,开机后设备又重新登录了一次,而造成同一台设备出现设备互踢现象
补充:强制关机时,设备端无法上报设备离线消息而导致的问题,所以由服务端解决该问题

物联网平台保活机制

MQTT保活机制
MQTT连接心跳时间为30秒至1,200秒。心跳时间不在此区间内,服务器将会拒绝连接。
建议取值300秒以上。
从物联网平台发送CONNACK响应CONNECT消息时,开始心跳计时。收到PUBLISH、SUBSCRIBE、PING或 PUBACK消息时,会重置计时器。超过指定1.5倍心跳时间未收到消息(指定心跳时间乘以1.5),服务器将自动断开连接。
云端是根据心跳判断设备是否离线的。每个连接都维持着一个最近活跃时间,任何mqtt上行报文都会刷新这个最近活跃时间。云端如果检测到一个连接的最近活跃时间与当前时间的差值,大于1.5倍的心跳时间,就会判定这个连接心跳超时,从而将这个设备踢下线。
举个例子,设备端连接时设置的心跳时间是60秒,那么设备端应用如果60秒被没有发业务报文,设备端sdk就应该自动发送一个ping报文。而对于云端来说,如果90秒内没有收到设备端的任何报文,就会将设备踢下线。
备注:目前云端的实际实现逻辑,是每隔30秒去检查下当前机器上的所有连接,所以实际的时间还会加上030秒。对于上面的例子,目前实际会经过90120秒后将设备踢下线。
1、SDK里面自带了重连机制,设备端没有必要自己去实现重连机制,如果自己要实现,就得从业务上
结合MQTT保活机制,自行评估合理性以及重连时机
2、另一方面云端判定心跳超时逻辑也是需要90~120秒的, 这个时候设备自己去重连又会造成互踢的现象

解决方案

方案一:

  • 服务端接收到上线信息,则通过redis设置1秒过期的key。
  • 服务端接收到下线信息,则获取该key:
    • 如果获取为空值则继续处理
    • 如果有值则不做处理

遇到的问题:服务端接受到的上线信息和下线信息时间间隔太短,导致redis缓存还未设置成功,下线信息就已经处理了,所以未能解决该问题。

方案二:

  • 服务端接收到上线信息时,设置程序睡眠1秒,先让下线信息处理后,再处理上线信息

以下为方案二潜在问题的思考,可能是想多了,欢迎评论区讨论:
并发高时,出现线程堵塞,在上线信息睡眠的1秒内,下线信息处于堵塞状态未处理,等上线信息睡眠结束处理完成(目前设备上线了),下线信息开始处理,此时还是会造成设备下线。

遇到的问题:AMQP服务使用了多线程,所以会概率出现上线信息和下线信息同时使用一个线程的情况,那么此时上线信息和下线信息则会是串行执行,所以还是未能解决该问题。

方案三:
结合方案一和方案二

  • 服务端接收到上线信息时,则通过redis设置3秒过期的key。
  • 服务端接收到下线信息时,且先设置程序睡眠1秒,保证能获取到redis的值,再获取该key:
    • 如果获取为空值则继续处理
    • 如果有值则不做处理
  • 29
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyoka丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值