MQTT会话是核心概念,使MQTT客户端与MQTT Broker之间即使在不稳定网络中也能可靠通信。在IoT环境中尤其重要,因为设备可能因省电模式、连接问题或网络变化而断开并重连。
MQTT会话存储 客户端 与 Broker 之间的交互相关状态。客户端重连时可复用该状态,使通信得以继续而无需从头重新初始化。
可将MQTT会话类比为酒店预订。
- 持久会话就像“预订房间”:即使外出用餐(断开),行李(订阅和未送达消息)仍留在房间等你回来。
- 非持久会话就像“临时入住”:离开大厅后,酒店不会保留你的任何信息。
持久会话
持久会话在客户端断开后保留会话状态,客户端重连时可恢复订阅和排队消息。
- 消息仅在会话活跃期间保留。若会话在重连前过期,任何排队消息将被丢弃。
- 此模式提高可靠性,但引入额外的确认和存储,增加系统复杂度。
- 持久会话需要 固定Client ID,以便Broker正确恢复会话状态。
- 离线消息投递仅适用于持久会话,且发布者和订阅者均需使用 QoS 1 或 QoS 2。对于不可接受消息丢失的应用,始终将持久会话与 QoS 1 或 QoS 2 结合使用(QoS文档)。
以下 信息可作为持久会话的一部分存储,并在会话过期或显式清除时移除:
- 会话及其关联的 Client ID 的存在
- 活跃 订阅,包括Topic Filter和Subscription Identifier
- 等待投递给客户端的 排队消息(QoS 1和QoS 2)
- 已发送但未完全确认的 传输中消息(QoS 1和QoS 2)
- 从客户端接收但尚未完全确认的QoS 2消息
- 配置的 Will Message 和 Will Delay Interval
- Session Expiry Interval 及计算出的会话过期时间
- 重连后正确恢复消息流所需的内部投递状态
非持久会话
非持久(clean)会话始终以全新状态开始。客户端断开时,Broker不保留任何会话状态。
- 订阅不被保留,每次连接时必须重新创建。
- 客户端离线期间发布的消息不会被存储或事后投递。
- 此模式开销最小,不需要消息确认或会话存储。
- Clean会话通常与QoS 0一起使用(也可用于更高QoS),在低延迟和简单性比保证投递更重要时适用。
Broker如何表示现有会话
客户端连接时,Broker通过CONNACK包中的Session Present标志告知是否存在先前的会话。
- Session Present = true。表示Broker已找到给定Client ID的现有会话并已恢复。订阅及所有存储的会话状态可供客户端使用。
- Session Present = false。表示未找到现有会话,已创建新会话。客户端需在需要时重新订阅。
该标志对使用 持久会话 的客户端尤其重要,使其能够判断是恢复先前会话还是从全新状态开始。
MQTT v3.x与MQTT v5.0的会话配置
相比 MQTT v3.x,MQTT v5.0 改进了会话管理。MQTT v3.x仅提供基本会话持久性控制,MQTT v5.0引入更灵活、显式的机制,更适合现代IoT系统,尤其是不稳定网络和大规模客户端场景。
关键变化是MQTT v5.0用两个独立属性 Clean Start 和 Session Expiry Interval 取代单一的 Clean Session 标志,使客户端能精确控制会话 何时 以全新状态开始,以及Broker在断开后 应保留 会话数据 多长时间。
| 会话类型 | MQTT v3.x 配置 |
MQTT v5.0 配置 |
说明 |
| 非持久会话 | Clean Session = 1 |
Clean Start = 1 Session Expiry Interval = 0 |
始终创建新会话。不存储订阅或消息。 客户端离线期间发布的消息会丢失。 适用于无需持久化的简单实时数据。 |
| 持久会话 | Clean Session = 0 |
Session Expiry Interval > 0 或 Clean Start = 0 Session Expiry Interval = 0 |
在断开后的一段时间内保留会话状态。 MQTT v5.0中Session Expiry Interval最大为 4,294,967,295秒(约136年)。 重连时恢复订阅和排队消息。 适用于间歇性连接且需控制资源使用的场景。 |
若未指定Session Expiry Interval,则默认为0。单位为秒。 Clean Start为布尔标志,等价于Clean Session,0表示false,1表示true。
关于在TBMQ UI中查看和管理MQTT会话的详情,请参阅 文档。
TBMQ中的会话状态管理
TBMQ设计用于在流量模式高度多样的环境中大规模运行,涵盖从轻量级IoT设备到高吞吐量后端应用。 TBMQ中的会话状态并非孤立管理。其生命周期、持久性及资源影响受客户端连接方式、产生的数据量、消费的数据量以及消息投递可靠性要求的影响。
客户端类型与会话行为
TBMQ通过将客户端分为 DEVICE 和 APPLICATION 两类来提升可扩展性和可靠性。 每种 客户端类型 具有不同的流量模式和预期用途,使TBMQ能为不同客户端类型采用定制的会话持久化和消息投递策略以高效使用资源。
| 客户端类型 | 会话类型 | 典型用例 | 持久性详情 |
| DEVICE | 非持久 |
简单环境监测。 示例:每分钟使用QoS 0发布一次的温度传感器。 |
无会话存储。断开时消息丢弃。设备重连后须重新订阅。若设备过慢,TBMQ会跳过消息,防止broker过载。 |
| DEVICE | 持久 |
命令投递和配置更新。 示例:在不稳定移动网络上的固件更新命令。 |
离线时消息排队。TBMQ将每个DEVICE会话存储的消息数限制为 65,535,并使用可配置TTL移除过期消息。 |
| APPLICATION | 非持久 | 通常不建议用于数据处理应用。 | 断开期间可能丢失消息。TBMQ向管理员显示数据丢失风险警告。 |
| APPLICATION | 持久 |
企业后端和分析系统。 示例:消费数千台设备的遥测数据。 |
专为极高吞吐量设计。支持共享订阅,可在多个应用实例间高效负载均衡。 |
会话配置参数
配置参数(参见Configuration properties)控制TBMQ如何处理持久会话和会话过期。它们定义影响消息保留、缓冲行为和非活跃客户端会话生命周期的限制与清理规则。
client-session-expiry参数控制非活跃会话允许存在的时间以及过期会话的定期清理,防止未使用的会话状态在系统中累积。persistent-session参数调节持久DEVICE和APPLICATION客户端的消息存储和投递,影响内存使用、吞吐量和投递延迟。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
client-session-expiry:
# Cron job to schedule clearing of expired and not active client sessions. Defaults to 'every hour', e.g. at 20:00:00 UTC
cron: "${MQTT_CLIENT_SESSION_EXPIRY_CRON:0 0 * ? * *}"
# Timezone for the client sessions clearing cron-job
zone: "${MQTT_CLIENT_SESSION_EXPIRY_ZONE:UTC}"
# Max expiry interval allowed of inactive sessions in seconds. The current value corresponds to one week
max-expiry-interval: "${MQTT_CLIENT_SESSION_EXPIRY_MAX_EXPIRY_INTERVAL:604800}"
# Administration TTL in seconds for clearing sessions that do not expire by session expiry interval
# (e.g. MQTTv3 cleanSession=false or MQTTv5 cleanStart=false && sessionExpiryInterval == 0).
# The current value corresponds to one week. 0 or negative value means this TTL is disabled
ttl: "${MQTT_CLIENT_SESSION_EXPIRY_TTL:604800}"
persistent-session:
device:
persisted-messages:
# Maximum number of PUBLISH messages stored for each persisted DEVICE client
limit: "${MQTT_PERSISTENT_SESSION_DEVICE_PERSISTED_MESSAGES_LIMIT:10000}"
# TTL of persisted DEVICE messages in seconds. The current value corresponds to one week
ttl: "${MQTT_PERSISTENT_SESSION_DEVICE_PERSISTED_MESSAGES_TTL:604800}"
# If enabled, each message is published to persistent DEVICE client subscribers with flush. When disabled, the messages are buffered in the channel and are flushed once in a while
write-and-flush: "${MQTT_PERSISTENT_MSG_WRITE_AND_FLUSH:true}"
# Number of messages buffered in the channel before the flush is made. Used when `MQTT_PERSISTENT_MSG_WRITE_AND_FLUSH` = false
buffered-msg-count: "${MQTT_PERSISTENT_BUFFERED_MSG_COUNT:5}"
app:
persisted-messages:
# Kafka topic properties separated by semicolon for `tbmq.msg.app` topics
topic-properties: "${TB_KAFKA_APP_PERSISTED_MSG_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;replication.factor:1}"
# If enabled, each message is published to persistent APPLICATION client subscribers with flush. When disabled, the messages are buffered in the channel and are flushed once in a while
write-and-flush: "${MQTT_APP_MSG_WRITE_AND_FLUSH:false}"
# Number of messages buffered in the channel before the flush is made. Used when `MQTT_APP_MSG_WRITE_AND_FLUSH` = false
buffered-msg-count: "${MQTT_APP_BUFFERED_MSG_COUNT:10}"
Message Expiry Interval与会话状态
Message Expiry Interval(MQTT v5.0)定义已发布消息在Broker将其丢弃前保持有效的时间。 它适用于每条消息,与客户端连接状态无关。
Message Expiry Interval在 Broker收到消息后 立即开始倒计时。 消息仅在未超过其过期时间间隔时才符合投递条件。 一旦间隔过期,消息将被丢弃且不再投递,即使会话仍然存在。
对于持久会话,Message Expiry Interval在离线消息排队中起关键作用:
- QoS 1或QoS 2的消息可在客户端离线时排队。
- 若排队消息在客户端重连前已过期,将从会话队列中移除。
- 这可防止投递过时数据,并限制持久会话中的长期消息累积。
对于非持久会话,Message Expiry Interval的实际作用有限:
- 仅在客户端连接时投递消息。
- 客户端离线时,无论过期设置如何,消息都不会排队。
Message Expiry Interval和Session Expiry Interval用途不同:
- Message Expiry Interval控制单条消息的有效期。
- Session Expiry Interval控制断开后会话状态的保留时间。
消息仅当会话仍存在 且 Message Expiry Interval尚未过期时才会被投递。
演示持久会话
本示例展示 持久会话 在实际中的工作方式,使用TBMQ WebSocket Client。 您将看到,客户端离线期间发布的消息 不会丢失,并在客户端重连时投递。
以下截图演示简单的IoT风格场景:
- 一客户端使用持久会话订阅某主题。
- 该客户端随后断开。
- 另一客户端向同一主题发布消息。
- 当第一客户端重连时,会收到其离线期间发布的消息。
此行为仅因会话为 持久 且消息使用 QoS 1 或 QoS 2 投递而成为可能。