MQTT中的持久会话允许客户端在断开连接时维护其会话状态,包括订阅的主题和未传递的消息。

非持久会话在断开连接时丢弃会话状态,要求客户端重新连接上再次订阅主题,并可能错过在断开连接期间发布的消息。

持久会话和非持久会话的选择取决于应用程序对会话连续性和消息持久性的要求。

持久会话的管理

当MQTT客户端与代理建立持久会话后,代理会保存客户端的订阅信息以及未传递的消息。

通过这种方式,如果客户端断开连接并在稍后重新连接,可以无缝地恢复通信。

在非持久会话中,如果客户端和代理之间的连接中断,则客户端将丢失其订阅信息,并且需要在重新连接时重新订阅。

会话由客户端在连接建立过程中提供的clientID来标识

持久会话的建立

在MQTT连接中,无论持久会话的建立还是清除都是由客户端来完成的。

客户端在建立连接(发送CONNECT报文)时,通过设置cleanSession标志来启用或关闭持久会话

工作原理如下:

  1. 当cleanSession标志设置为1时,MQTT客户端显式请求非持久会话。在这种情况下,如果客户端与代理断开连接,则来自之前持久会话的信息都将被丢弃。重新连接后,客户端将从头开始。
  2. 当cleanSession标志设置为0时,MQTT代理会为客户端创建持久会话。这意味着即使客户端离线,代理也会保留所有相关信息和消息,直到客户端明确请求清理会话。
    1. 如果代理已经有一个之前该客户端的会话信息,那么代理使用CONNACK报文(Session Present标志为1)通知客户端已存在会话信息,并使用该会话与客户端建立连接,连接建立成功后将之前排队的消息传递给客户端
    2. 如果代理对该客户端没有保存过会话信息,那么代理使用CONNACK报文(Session Present标志为1)通知客户端不存在之前的可用会话,并与客户端创建新的持久会话,并保存相关信息

会话状态同步

MQTT3.1.1之后,代理响应客户端连接请求CONNACK报文而发送的CONNACK报文中包含会话存在标志(Session Present)。

该标志用于通知客户端其之前建立的会话在代理上是否仍然可用

通过检查会话存在标志,客户端可以确定是建立新会话还是重新连接到现有会话。

消息存储时间

MQTT代理存储会话信息以及消息的时间主要取决于以下两个因素:

  1. 代理进程可用的内存大小。
  2. 用户根据实际情况手动配置的相关参数。例如,emqx中默认存储1000条消息,但是可以手动修改。

保存内容

MQTT代理

在持久会话中,代理会存储以下信息(即使客户端处于离线状态),当客户端重新连接后,会立即获得此信息:

会话存在标志(Session Present)

MQTT代理会保存会话存在的信息。

客户端使用cleanSession=0重新连接成功之后,MQTT代理会判断是否已有之前的会话信息。

  1. 如果有,则在CONNACK报文中设置SessionPresent标志为1,用于表示存在之前的会话可用,随即与客户端使用之前的会话建立连接。
  2. 如果没有,则在CONNACK报文中设置SessionPresent标志为0,表示没有之前的可用会话,与客户端建立新会话。

客户端已订阅的主题列表

用于确保客户端无需在每次重新连接时重新订阅相同的主题,从而节省宝贵的时间和资源。

客户端尚未确认的消息(QoS1和QoS2级别)

MQTT代理在发送QoS1或QoS2级别消息给订阅客户端时,需要等待客户端进行确认。

如果客户端在进行确认之前丢失连接,MQTT代理会视为消息发送失败,进而将这些消息存储起来,等待客户端再次连接发送,以确保消息的可靠传递。

客户端离线时错过的消息(QoS1和QoS2级别)

在MQTT订阅客户端使用QoS1或QoS2订阅主题列表之后丢失连接再到重新连上这段时间内,MQTT代理如果收到发布客户端发送到该主题列表的消息,则会以队列的形式为订阅客户端存储这些消息。

一旦订阅客户端重新连上,就会接收排队的消息,从而防止丢失重要信息。

来自客户端等待完整确认的消息(QoS2级别)

在QoS2级别通信过程中,当MQTT代理收到PUBLISH报文之后,会返回给发布客户端PUBREC报文用于告知发布客户端已收到消息。

如果此时发布客户端丢失连接,那么MQTT代理则会保存该消息,以等待发布客户端重新连接成功,并发布PUBREL用于释放PacketId。

换句话说,MQTT代理会保存未完整确认的消息,直到发布客户端完成确认流程。

MQTT客户端

处理MQTT代理存储持久会话的相关信息之外,客户端也会存储一些相关信息。

代理未确认所有消息(QoS1和QoS2级别)

当MQTT发送客户端使用QoS1或QoS2发送PUBLISH报文之后,会等待代理返回确认报文PUBACK或PUBREC报文。

如果MQTT发送客户端在等待确认报文的过程中丢失连接,则这些消息会存储在本地,直到代理重新连接并受到确认报文才算传输完成。

通过维护这些未确认的消息,客户端确保可以在必要时重新传输任何消息并达到所需的可靠性级别。

来自代理未完成确认的消息(QoS2级别)

当MQTT代理发送完PUBLISH报文,订阅客户端会收到该报文并存储起来,防止由于连接丢失导致无法收到后面的用于PacketID释放报文PUBREL。

当收到MQTT代理发送的PUBREL报文之后,订阅客户端就可以释放存储的PUBLISH报文以及PacketID了。

使用建议

持久会话的使用场景

  1. 确保消息可靠性:即使客户端离线也要能够接收到所有消息。
  2. 资源优化:客户端资源有限,将会话信息以及消息存储在代理上。
  3. 恢复发布:客户端掉线重连之后需要恢复发布QoS1或QoS2的消息。

CleanSession的适用范围

  1. 仅用于发布的客户端
  2. 不需要接收离线消息。