MQTT-保留消息和遗嘱消息

科技资讯 投稿 5600 0 评论

MQTT-保留消息和遗嘱消息


保留消息

为什么需要保留消息

如何使用保留消息

​ 我们可以在发送PUBLISH的时候把Retain设置为1或者True,表示当前消息是保留消息,保留消息进入服务端,会像普通消息一样转发给当前的订阅者,还会被保留在MQTT的服务端中,每当有新的订阅建立,MQTT服务端都会检索是否存在与这个订阅匹配的保留消息,然后把匹配的保留消息下发给订阅者,由于订阅的时候可以使用主题通配符,所以可能匹配到多个保留消息,这些消息将依次下发给订阅者

保留消息的更新

​ 需要注意的是,QoS 0 可能丢消息的特性,可能会导致保留消息删除不成功,QoS 1 可能重复到达的特性,保留消息又可能多次删除,如果不希望出现删除失败或者多次删除的情况,可以使用QoS 2 来发布 payload为空的保留消息

保留消息的过期时间

保留消息的发送机制

​ 默认情况下,当保留消息当成普通消息向订阅者转发的时候,保留消息中的retain标识会被清除也就是设置为0,只有当新的订阅建立的时候,发送保留消息的retain会设置为1,表示这是一个保留消息

​ 还有一个选项会影响保留消息的行为,在某些场景下,虽然客户端复用了上一次的会话,但是无法确定上一次会话中是否成功订阅了某个主题,所以只能再次订阅,如果订阅已经存在,其实服务端已经给客户端缓存了离线期间的消息,这种情况下,客户端在重连后,其实并不需要获取保留消息,但是现在只要有订阅建立,订阅匹配就会下发保留消息,为了解决这个问题,在MQTT 5.0中,提供了 Retain Handling的订阅选项

    Retain Handling = 0,订阅建立的时候发送保留消息
  • Retain Handling = 1,订阅建立时若该订阅当前不存在则发送保留消息
  • Retain Handling = 2,订阅建立时不发送保留消息
保留消息的注意事项
    在MQTT中,同一条普通消息只能被同一个客户端消费一次,保留消息可能会被重复消费,客户端进行订阅,服务端下发匹配的保留消息,即时这个消息之前已经下发过了,只要保留消息在客户端的两次订阅期间没有更新,客户端就会重复消费到同一条消息,如果客户端的订阅是在保留消息到达服务端之前建立的,消息转发后 客户端重新连接,没有更新过保留消息,就是重复收到了两条同样的消息
  • 不能通过主动删除已经消费过的保留消息来避免重复,因为可能其他人也使用该主题下的保留消息,我们就不能去删除他,其次也没有办法正确判断当前服务器中的保留消息有没有被自己消费过,我们可以参考QoS 1 去重的做法,在保留消息的payload中增加一个时间戳,订阅者记录最后消费的消息的时间戳,和新到达的保留消息的时间戳进行比较,如果后者的时间戳更新,就是一个新的消息,反之就是一个重复的消息
  • 我们可以通过保留消息减少消息的发布频次,对于一些固定周期、状态等以确保新上线的客户端尽快取得数据,有了保留消息,我们可以只在状态发生变更时进行发布

遗嘱消息

为什么需要遗嘱消息

如何使用遗嘱消息

​ 使用遗嘱消息,客户端需要在连接时,也就是connect报文中指定遗嘱消息,除了正常CONNECT报文字段,需要为遗嘱消息提供以下字段

Will Topic #遗嘱消息主题

Will QoS  # 遗嘱消息级别

Will Retain  # 将遗嘱消息设置为保留消息
'''
遗嘱消息一旦发布,就会在服务端的会话状态中删除,不能多次消费,我们不能保证遗嘱消息发出的时候订阅端是否在线,为了避免错过遗嘱消息,可以使用Will Retain = True 字段将遗嘱消息设置为保留消息,这样订阅了该主题的客户端不管什么时候上线,都可以收到另外一方的离线通知
'''

Will Properties # 遗嘱消息属性  ↓

Will Delay Interval #遗嘱消息的属性↑, 设置遗嘱消息的延迟发送时间
'''
在MQTT 5.0中,可以使用 Will Delay Interval 设置延迟发送遗嘱消息,单位是S,如果客户端及时恢复,那么遗嘱消息的发生倒计时就会终止,可以避免客户端在短暂离线后恢复,可以继续服务时但是遗嘱消息已经发出的情况,和保留消息不同的是,遗嘱消息是会话状态的一部分,没有办法存在比会话更长的时间,如果遗嘱延迟时间大于会话过期时间,会话结束的时候遗嘱会立即发布
'''

Will Payload  # 遗嘱消息内容

​ 在客户端连接成功后,遗嘱消息就会存储在服务端中,一旦客户端连接异常断开,服务端就会把遗嘱消息发送给对应的订阅者,如果客户端是正常断开,遗嘱消息则不会发布,在MQTT中,客户端的意外断开可以分为以下几种情况

    服务端检测到了一个I/O故障或者网络故障
  • 客户端在心跳的时间内未能通讯
  • 客户端在没有发生Reason Code 为0的DISCONNECT报文的情况下关闭了网络连接
  • 服务端在没有收到DISCONNECT报文的情况下主动关闭了网络连接
  • 在MQTT 3.1.1中,如果满足任意一个情况,服务端会在连接断开后立刻发布遗嘱消息,5.0中可以通过设置属性延迟发布

编程笔记 » MQTT-保留消息和遗嘱消息

赞同 (27) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽