本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。
多路分解
一个连接承载所有订阅:订阅标识符区分重叠的过滤器,同一个过滤器上的订阅轮流接收投递。
以文字阅读本图
- 连接上的过滤器: devices/+/telemetry 标识符 17; 接收它 (轮到它); 接收 下一个; devices/# 标识符 42; 唯一的订阅 接收每一个
- PUBLISH devices/dev42/telemetry 标识符 17 → devices/+/telemetry 标识符 17
- devices/+/telemetry 标识符 17 → 接收它 (轮到它)
- devices/+/telemetry 标识符 17 → 接收 下一个: 下一个
- PUBLISH devices/dev42/telemetry 标识符 42 → devices/# 标识符 42
- devices/# 标识符 42 → 唯一的订阅 接收每一个
- 没有已打开订阅认领的报文最多暂存 1024 个, 等待之后打开的订阅
服务器在每个连接上只订阅一个过滤器一次。同一过滤器上的两个处理器,或同一服务中共享组的两个成员,在服务器上是一个订阅,在服务中是两个订阅。本 crate 把该过滤器的投递轮流交给它们。只要其中任何一个还开着,过滤器就保持订阅;服务停止时,过滤器留在会话中。订阅采用它们之中要求最高的服务质量。
不同但可能匹配同一主题的过滤器,例如 devices/+/telemetry 与 devices/#,或者共享组与同一过滤器上的普通订阅,在服务器上是彼此独立的订阅。对于同时匹配两者的消息,Mosquitto 为每个订阅各发送一个报文。MQTT 5 允许订阅携带一个标识符,服务器在为该订阅发送的每个报文中都会给出它。本 crate 只给与连接上另一个过滤器重叠的过滤器分配标识符,并按报文给出的标识符转交每个报文。
在订阅之后才与另一个过滤器重叠的过滤器,会带着标识符重新订阅,并且这一次不向服务器请求保留消息,这样保留消息不会被投递两次。标识符由过滤器本身推导而来。因此,重启后恢复持久会话的服务,会给每个过滤器分配服务器仍然持有的那个标识符。
订阅标识符对服务器来说是可选的,服务器的 CONNACK 会说明是否提供。在不提供的服务器上,如果在同一连接上打开与另一个过滤器重叠的过滤器,就会在订阅任何内容之前返回一个指出这两个过滤器的错误。使用各自客户端 ID 的两个 Broker 可以把这样的过滤器分开。当服务器为两个过滤器只发送一个报文时,交给第一个过滤器的投递负责确认,另一个投递的 ack 返回 AckError::Unsupported。
没有已打开订阅认领的报文会被暂存,因为恢复的会话会在服务打开其所属订阅之前就发送积压的消息。最多 1024 个报文等待,超过之后,最旧的报文被丢弃,并记录一条警告。
工作分区
以文字阅读本图
- 订阅 共享连接上的一个主题或过滤器 → MqttSubscriber 流 一次一个投递: 投递
- MqttSubscriber 流 一次一个投递 → workers(2) 工作分区轮流接收投递: 一次一个
- workers(2) 工作分区轮流接收投递 → 工作分区 1 按顺序运行它的投递
- workers(2) 工作分区轮流接收投递 → 工作分区 2 按顺序运行它的投递
- by_key:同一个 partition-key 值走同一个工作分区; 没有该头的投递轮流进入下一个
- 跨进程:共享组 把每条消息交给一个成员
不用 workers 时,一个循环依次为订阅的每个投递运行处理器。服务器发送它们的顺序得以保持,也没有任何东西并行运行。
workers(n) 运行 n 个工作分区,每个工作分区按顺序运行自己的投递。工作分区轮流接收投递,所以同一主题的投递在不同的工作分区上并行运行。在 workers(n, by_key) 下,由发布者设置的 partition-key 头 选择工作分区:同一个键的投递按顺序运行,没有该头的投递轮流进入下一个工作分区。
跨进程时,由共享组划分消息:服务器把每条消息交给一个成员。Receive Maximum 限制一个连接在其所有订阅中同时持有的未确认 QoS 1 和 QoS 2 投递数。
批处理器最多接收挂载点指定的大小。一个 PUBLISH 只携带一条消息,所以本 crate 在客户端组装批。批达到该大小,或在第一个投递之后 20 毫秒时结束。