首页 > 其他分享 >MQTT-保留消息和遗嘱消息

MQTT-保留消息和遗嘱消息

时间:2023-05-09 16:56:45浏览次数:37  
标签:订阅 保留 MQTT 消息 遗嘱 服务端 客户端


保留消息

为什么需要保留消息

       如果不考虑持久会话的因素,那么MQTT订阅只有在客户端连接之后才能创建,所以服务端不能提前预知某个主题会被哪些服务端订阅或者某个客户端会订阅哪些主题,所以当消息到达服务端之后,服务端只会把消息分发给当前已经存在的订阅者,分发完成消息就会从服务端中删除,如果当前没有任何订阅者,消息就会立即丢弃,如果订阅端在在这之后上线的,就会错过这个消息,为了解决该场景的问题,MQTT提供了保留消息

如何使用保留消息

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

保留消息的更新

       通过保留消息,我们可以使订阅者上线后立即获得数据更新,不必等待新一次的消息,每个主题最多可以储存一条保留消息,如果主题下的保留消息已经存在,那么新到达的保留消息就会替换原来的保留消息,保留消息会一直储存在服务端中,由于他不属于会话状态的一部分,所以即便发布端会话过期,也不会影响保留消息存储,如果想要清空这个主题的保留消息,可以通过发送一个payload为空的保留消息来实现,这个为空的保留消息会合其他保留消息一样转发给订阅者,区别是在于不会被服务端存储,使用这种方式的话,我们需要确保订阅端不会把为空的消息视为一个错误

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

保留消息的过期时间

       如果担心一条保留消息失去了时效性,还长时间保留在服务端中导致被后来的订阅者消费的话,MQTT 5.0版本可以为保留消息设置过期时间,PUBLISH的 Message Expiry Interval 属性,单位是秒

保留消息的发送机制

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

       针对上述情况多个服务端桥接的时候,会衍生一个问题,比如服务端A向服务端B订阅了主题,当服务端B收到一个保留消息向服务端A转发的时候清除retain标识,导致服务端A收到该保留消息后只会转发给订阅者,不会保存保留消息,在MQTT 5.0中,提供了 Retain As Published 的订阅选项,如果该选项设置为0,就是默认的逻辑,如果设置为1,那么保留消息当做普通消息转发的时候,Retain标识不会被清除,依然是1

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

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

遗嘱消息

为什么需要遗嘱消息

       MQTT的订阅发布机制,解耦了消息的发送方和接收方,这使我们没有办法获取对端的状态,为了解决该问题,MQTT提供了遗嘱消息,为意外断线的客户端提供了对外发出通知的能力

如何使用遗嘱消息

       使用遗嘱消息,客户端需要在连接时,也就是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,消息,遗嘱,服务端,客户端
From: https://www.cnblogs.com/Mickey-7/p/17385599.html

相关文章

  • 小程序订阅消息收不到
    1、检查下小程序公众平台是否开通了订阅消息2、订阅消息需要全部配置才可以生效。3、全部配置完成后,需要小程序清除全部缓存,从新加载。因为小程序内的订阅消息id是缓存在小程序中的;4、小程序特定事件,比如支付下单是否有订阅弹窗5、如果没有:(在开发工具查看有一个config接口反馈订阅......
  • 手把手带你实现事务消息
    1、本文2个目的1、讨论一下消息投递的5种方式2、带你手写代码,实现事务消息的投递2、讨论一下消息投递的5种方式2.1、业务场景电商中有这样的一个场景:商品下单之后,需给用户送积分,订单表和积分表分别在不同的db中,涉及到分布式事务的问题。我们通过可靠消息来解决这个问题:商......
  • 消息通知
    https://blog.csdn.net/fegus/article/details/124314455https://chengxy-nds.blog.csdn.net/article/details/108390222?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-108390222-blog-112081179.pc_releva......
  • Rabbitmq介绍,安装,基于queue实现消费者生产者,基本使用,消息安全,持久化,闲置消费,发布订阅,
    内容详细Rabbmit介绍消息队列中间件概念很大,准确一些叫消息队列中间件消息队列中间件使用redis当作消息队列来用,blpop阻塞式弹出,实现队列,先进先出MQ,消息队列,MessageQueue是什么?消息队列就是基础数据结构中先进先出(队列)的一种数据机制,类比于生活中,买东西,需要排队,先排队的人......
  • RocketMQ之事务消息
    一、概述ApacheRocketMQ在4.3.0版中已经支持分布式事务消息,通过消息的异步事务,可以保证本地事务和消息发送同时执行成功或失败,从而保证了数据的最终一致性。二、案例根据官方提供的例子,TransactionProducer.java如下:publicclassTransactionProducer{publicstaticf......
  • RocketMQ之消息发送源码分析
    一、概述负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ支持三种消息发送方式:同步消息发送(sync):当Producer发送消息到Broker时会同步等待消息处理结果;异步消息发送(async):当Producer发送消息到Broker时......
  • RocketMQ之消息接收源码分析
    一、概述对于任何一款消息中间件而言,消费者客户端一般有两种方式从消息中间件获取消息并消费:Push方式:由消息中间件(MQ消息服务器代理)主动地将消息推送给消费者;采用Push方式,可以尽可能实时地将消息发送给消费者进行消费。但是,在消费者的处理消息的能力较弱的时候(比如,消费者端......
  • RabbitMQ - 消息中间件
    RabbitMQ-消息中间件目录RabbitMQ-消息中间件1消息队列Rabbitmq介绍1.0什么是消息队列1.1rabbitmq介绍1.2MQ解决的问题1.3常见的消息队列及比较2RabbitMQ介绍安装2.1下载2.2安装(1)window安装(2)linux下安装rabbitmq(3)docker安装2.3配置web管理插件(1)windows配置(2)centos7......
  • 消息队列Rabbitmq介绍、rabbitmq安装、基于queue实现生产者消费者、基本使用、消息安
    目录1消息队列Rabbitmq介绍2rabbitmq安装3基于queue实现生产者消费者4基本使用4.1发送者4.2消费者5消息安全(详见笔记)6持久化(详见笔记)7闲置消费(详见笔记)8发布订阅(详见笔记)9发布订阅高级之Routing(按关键字匹配)(详见笔记)1消息队列Rabbitmq介绍#消息队列 -......
  • RocketMQ之消息轨迹
    一、概述消息轨迹是用来跟踪记录消息发送、消息消费的轨迹。如何启用消息轨迹?broker端需要在broker端的配置文件中添加配置项:traceTopicEnable=true,注意:对于消息轨迹数据量较大的场景,可以在RocketMQ集群中选择其中一个Broker节点专用于存储消息轨迹,使得用户普通的消息数据与......