MQTT中QOS=2的四次包交互

MQTT协议在我们工作中经常用到,MQTT有三种QOS,分别为At most once delivery、At least once delivery、Exactly once delivery,每种服务质量包交互次数各不相同,前两种较好理解,但是QOS=2时为什么需要四次包交互呢?我们一起探讨下。

我们假设分别使用两次、三次、四次包交互看看什么区别:

1.只采用两次包交互
在这里插入图片描述

1、publisher 推送msg到server,server立即存储msg到内存或数据库中

2、server 回复ack与msgId给publisher,publisher确认服务器收到推送后删除msg

3、server推送msg到subscriber,subscriber立即保存msg

4、subscriber回复ack与msgId给server,server确认subscriber收到消息后删除msg

包丢失的情况:

1、publisher推送msg到server时,包丢失。因为publisher没有收到ack消息,一段时间后,publisher超时重发publish消息。

2、server回复publisher时,ack包丢失。因为publisher没有收到ack消息,一段时间后,publisher超时重发publish消息。server收到publish消息后,又重新发送ack消息。

3、server推送msg到subscriber时,包丢失。因为server没有收到ack消息,一段时间后,server超时重发publish消息。

4、subscriber回复server时,ack包丢失。因为server没有收到ack消息,一段时间后,server超时重发publish消息。subscriber收到publish消息后,又重新发送ack消息。

Exactly once delivery如何保证?

publiser端发送到server与server端发送到subscriber端是异步的,只需保证每一步消息都是恰好只收到一次,则保证了subscriber只收到了一次。事实上,这里通过server端与subscriber端保存msg,当消息重复推送时,可以在接收端相应的去重,从而做到只接收到一次。

缺点:

IBM MQTT官网关于messageID字段设计
只有两次包交互看似已经完成了Exactly once delivery,但是subscribe端没有释放messageId,因为subscriber端不知道server是否收到subscriber发出的ack消息,所以需要一直保存msg或者msgId,来对server端超时重发的msg去重。而我们看到messageID的设计只有2个字节长度,也就是65535个,如果subscribe一直不删除本地messageID,那第二轮的messageID会冲掉第一轮的messageID,因此必须释放本地messageID。为什么把messageID设计的这么小呢,因为MQTT就是为那些小的硬件设备设计的,他们没有足够的内存与磁盘保存海量的msg。从上面可以看出来,两次交互不够,至少还需要一次交互告诉subscriber删除本地msg。对于server端也是如此,server也需要一直保存msg来防止publisher重发。

2.采用三次交互
在这里插入图片描述
1、publisher 推送msg到server,server立即存储msg到内存或数据库中

2、server 回复recive与msgId给publisher

3、server推送release与msgId到server,表示已经知道server收到msg了,后续不会再发送msg了,告诉server可以释放消息了,随即publisher删除msg

5、server推送msg到subscriber,subscriber立即保存msg到内存或数据库

6、subscriber回复recive与msgId给server

7、server推送release与msgId到subcriber,表示已经知道subscriber收到msg了,后续不会再发送msg了,告诉subscriber可以释放消息了,随即server删除msg

8、subscriber把msg转发给上层应用,随即删除msg

缺点:

无法保证release包一定能被server和subscriber接收,server端一直保留messageID就可能丢失下一轮次从publisher推送过来的相同messageID。因此还需要一次交互,来保证server、subscriber收到了release包,若没收到,则进行重传。总结下,subscribe端不清除messageID可能导致消息丢失,server端不清除messageID也可能导致消息丢失,要让他们两个同时清除该怎么办,这就是一个二将军问题了,二将军问题已经被证明是无解的,因此MQTT的做法是再使用三次包交互来基本保证同时删除。

3、采用四次包交互:
在这里插入图片描述
四次交互在三次交互基础上增加了一个pubcomp包,当publiser与server收到pubcomp包后,表示接收端已经收到release包了,因此可以删除msg了。到此,QOS=2实现了包的去重与msgid的可重用。

总结:

1、publisher发送到server与server发送到subscriber是异步的,互不影响。

2、publish、pubrec包实现了消息的至少传达一次,又通过内存或磁盘数据去重,实现只有一次传达。

3、pubrec、pubrel、pubcomp包用来及时清理msg与msgid,避免内存或磁盘数据过大,实现msgid可重用。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值