跳到主要内容
英文版本为准

本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。

设计

ruststream-rumqttc 所处的位置:在 RustStream 运行时与 rumqttc 客户端之间,使用一个由它自己的任务驱动的连接。

自上而下依次是服务、RustStream 运行时、本 crate、rumqttc 客户端和 MQTT 服务器你的服务RustStream 核心ruststream-rumqttcrumqttc#[subscriber]订阅者处理器RustStream::new(..).with_broker(..)运行时:分发、工作分区、结算、重试MqttSubscriber产出 MqttMessageMqttPublisher由策略生成上下文:DeliveryTopic进程内传输MqttBroker一个连接MqttTopic,MqttFilter连接任务:转交每个 PUBLISHEventLoop负责读写AsyncClient接收请求MQTT 服务器
以文字阅读本图
  1. 你的服务: #[subscriber] 订阅者处理器; RustStream::new(..) .with_broker(..)
  2. RustStream 核心: 运行时:分发、工作分区、结算、重试
  3. ruststream-rumqttc: MqttSubscriber 产出 MqttMessage; MqttPublisher 由策略生成; 上下文:DeliveryTopic; 进程内传输; MqttBroker 一个连接; MqttTopic, MqttFilter; 连接任务: 转交每个 PUBLISH
  4. rumqttc: EventLoop 负责读写; AsyncClient 接收请求
  5. #[subscriber] 订阅者处理器 → 运行时:分发、工作分区、结算、重试: 挂载到
  6. 运行时:分发、工作分区、结算、重试 → MqttSubscriber 产出 MqttMessage: 轮询流
  7. 连接任务: 转交每个 PUBLISH → MqttSubscriber 产出 MqttMessage
  8. 连接任务: 转交每个 PUBLISH → EventLoop 负责读写: 轮询
  9. MqttPublisher 由策略生成 → AsyncClient 接收请求
  10. AsyncClient 接收请求 → EventLoop 负责读写
  11. EventLoop 负责读写 → MQTT 服务器

本 crate 在 rumqttc 之上实现核心的 Broker trait,只使用 MQTT 5。它上面的运行时对每个 Broker 都相同。MQTT 特有的一切都在本 crate 里:描述符、ack 发送什么、重试副本发往何处、投递的主题,以及消息头到 MQTT 5 属性的映射。消息头使用协议自己的属性,因此用任何语言编写的对端读到的都是普通的 MQTT 消息。

rumqttc 把一个连接分成两半。AsyncClient 是一个可克隆的句柄,负责把请求排入队列:订阅、发布、确认。EventLoop 把这些请求写入套接字,并读取服务器发来的内容,而且只在有人轮询它时才做这两件事。keep-alive 的 ping 和确认的发出,也都靠轮询来推动。

已连接的 Broker 持有一对这样的对象。本 crate 在连接时启动一个自己的任务,在上面轮询事件循环。这个任务只做轮询和转交。因此慢速处理器永远不会阻塞连接:ping、确认以及其他订阅的投递都照常进行。订阅、发布和确认通过 AsyncClient 进行,在哪个任务里调用,就在哪个任务里执行。

连接任务把服务器发来的每个 PUBLISH 交给它所属的订阅,每个订阅一个通道。Broker 的所有订阅和发布者共用这一个连接,所以一个有许多处理器的服务在服务器上只持有一个会话。多路分解一页用图说明一个连接如何区分它的订阅。

各部分如何启动和停止,见生命周期;一条消息的路径,见路径。

进程内传输​

启用 testing 特性后,TestApp::start 把同一个 Broker 连接到进程内传输,而不是服务器。描述符、策略和投递都与生产环境相同,传输读取 Broker 自己的设置。发布经过与线上相同的校验,消息头也以相同的方式映射到属性上。

这个传输模拟的是该连接所对接的服务器。它用 + 和 # 匹配过滤器,并遵守 $ 规则。它以较低的服务质量为每个匹配的订阅发送一个报文,并带上该订阅的标识符,每个报文都经过连接任务所执行的同一套多路分解。因此,共享组的成员之间只取一份副本,重叠的过滤器各自收到属于自己的一份。它保存每个主题的保留消息,丢弃大于 max_packet_size 的消息,并在关闭后拒绝确认。

属于服务器和第二个连接的行为只在线上运行:持久会话及其恢复时的重新投递、遗嘱消息、Receive Maximum 窗口、QoS 1 和 QoS 2 握手、访问控制,以及一台服务器上的多个连接。每个以进程内方式连接的 Broker 都是一台独立的服务器。

不启用该特性时,传输不会被编译。生产构建中的连接句柄与它所包装的 AsyncClient 大小完全相同,编译器会检查这个大小。