设备发送mqtt消息到服务器的频率和消费接收消息频率不一致问题

159 阅读4分钟

项目上和设备供应商联调对接设备的时候,对方的技术明确了消息发送的频率是一秒一次,我进行数据采集的时候,消费对应的topic采集的数据却是5分钟一次,严重阻碍后续项目进行

  1. 排查思路:先进入emqx的mqtt服务器管理后台客户端查询topic消息:这里可以看到消息的接收报文数和字节大小每秒都是递增的,因此当时我排除了发送端的问题

image.png 2. 排除是否是消费端的问题:这个也很好操作,自己启用一个客户端定时一秒发送消息进去,还是之前的消费程序消费消息,结果显示可以一秒一次的频率接收消息,到这里可以排除消费端的问题了

  1. 最后只能是服务器端broker的设置问题,然后我在后台设置找到这么一个配置项:这个正好是5分钟,试着修改了一下,改成30秒,这消费端接收频率为30秒,改成一秒则接收频率变成一秒,OK问题定位到了

image.png 4. 最后结合之前为了应对找工作面试而看的一些mqtt协议的知识,我瞬间想起来导致这个问题的原因了,说到底根源还是在供应商消息发送方那边.

mqtt发送时候设置qos,qos三个等级 qos=0的时候:发送方只发送一次,这个好理解,没什么讲的

image.png qos=1的时候:这个是用来保证消息只发送一次,不会重复发送,但是不能保证消费端不重复消息的问题 但是消息传递流程中可能会出现问题:

  • 如果Sender在一段时间内没有收到PUBLISH包对应的PUBACK,它将该PUBLISH包的DUP标识设为1(代表是重新发送的PUBLISH包),然后重新发送该PUBLISH包。
  • Receiver可能会重复收到消息,需自行去重。

image.png qos=2的时候:相比QoS0和QoS1,QoS2不仅要确保Receiver能收到Sender发送的消息,还需要确保消息不重复。它的重传和应答机制就要复杂一些,同时开销也是最大的。QoS2下,一次消息的传递流程如下所示: 相比QoS0和QoS1,QoS2不仅要确保Receiver能收到Sender发送的消息,还需要确保消息不重复。它的重传和应答机制就要复杂一些,同时开销也是最大的。QoS2下,一次消息的传递流程如下所示:

  1. Sender发送QoS为2的PUBLISH数据包,数据包 Packet Identifier 为 P,并在本地保存该PUBLISH包;
  2. Receiver收到PUBLISH数据包后,在本地保存PUBLISH包的Packet Identifier P,并回复Sender一个PUBREC数据包,PUBREC数据包可变头中的Packet Identifier为P,没有消息体(Payload);
  3. 当Sender收到PUBREC,它就可以安全的丢弃掉初始Packet Identifier为P的PUBLISH数据包。同时保存该PUBREC数据包,并回复Receiver一个PUBREL数据包,PUBREL数据包可变头中的Packet Identifier为P,没有消息体;
  4. 当Receiver收到PUBREL数据包,它可以丢掉保存的PUBLISH包的Packet Identifier P,并回复Sender一个可变头中 Packet Identifier 为 P,没有消息体(Payload)的PUBCOMP数据包;
  5. 当Sender收到PUBCOMP包,那么认为传输已完成,则丢掉对应的PUBREC数据包; image.png 上面第4步Reciver接收PUBREL数据包有一个超时等待最大时间的,如果发送方一直不发送或者消息包丢失了,是要默认丢掉第二步中保存的PUBLISH包的Packet Identifier P的,这个时候消息会被释放出来,然后才能被消费,所以才出现了消费频率变成了5分钟,就是这个设置的最大 PUBREL 等待时长 原因很明显了,就是供应商的物联设备不具备qos=2的保证消息质量的能力,发送消息的时候却设置成了qos=2,导致mqtt服务端按照qos=2的消息处理逻辑严格执行确保不重复消费的,一直等待发送方回传确认包,知道等待超时,因此消费频率不一致 最后的解决办法:直接让供应商设备修改烧录的消息发送程序,qos改成0就好了,这是最正规的解决办法,然后最简单粗暴的解决办法就是把mqtt服务器的PUBREL等待时长设置为你1s,这个只能应对这一个场景 问题完美解决,经过这次,可以发现,平时多看看各种机制原理是有帮助的,定位问题的时候,你的脑子会思考各种可能情况,原理只需要留下一点点印象在你脑子里就够了,遇到问题的时候你可以回去重新看是不是这个原理导致的,这是我入行物联网的解决的第一个实战遇到的问题