【译文】MQTT的发布/订阅架构-MQTT基础:第二部分

97 阅读17分钟

原文:www.hivemq.com/blog/mqtt-e…

本篇文章在翻译过程中,对相关内容进行了一些删减,比如文字超链接

作者:HiveMQ Team
发布时间:January 19, 2015
更新于:2023年6月6日

欢迎来到MQTT基础课程的第二部分,基础课程共分10部,涵盖MQTT协议的核心特性,概念,优势。本篇文章将深入研究"发布/订阅"(Pub/Sub)架构,也可表示为pub/sub, 它是软件体系结构中的一种消息匹配模式,能够以解耦的方式在不同组件或系统之间进行通信。

在基础课程第一部分中,我们介绍了一些MQTT的基础概述和它的历史。现在,让我们探究一下"发布/订阅"模型对IoT应用所能带来的好处以及过滤各种消息的技术,了解MQTT,"发布/订阅"和消息队列之间的区别。为了打好基础,我们将开始明确“发布/订阅”(publish/subscrbe)模型的定义。

MQTT: 发布/订阅架构【英文表示:Publish/Subscribe 或 Pub/Sub】

在Pub/Sub架构中,包含能生成消息的发布者和能接收这些消息的订阅者。因此,发布-订阅 是一个比较宽泛的概念,它可以使用多种协议或者技术来实现。

MQTT是一种遵循“发布-订阅”架构的特殊消息协议  MQTT采用代理模型思想完成客户端和代理服务器之间的连接,然后把消息发布到主题。订阅者可以订阅指定主题,然后就可以接收已发布的消息。

WX20230907-191821@2x.png MQTT 发布/订阅 架构样例

MQTT: 发布/订阅 的解耦特性

“发布/订阅”架构对于传统的“客户端-服务器”(请求-响应)模型提供了一个独特的选择。在“请求-响应”模型中,客户端和服务端点对点通信,从而引起性能瓶颈。相反,发布-订阅 模型可以将消息发布者和订阅解耦分离,发布者和订阅者相互之间是不知道对方的存在。作为第三个组件,代理服务器会处理它们之间的连接,这种解耦方式提供了更快、更有效的通信过程。

通过排除发布者和订阅者之间的直接通信方式,发布/订阅架构移除了IP地址及端口的交互过程,因此这种架构具有解耦特性,允许组件之间在发布主题过程中或者接收主题过程中连续通信而不被中断。为了实现最佳效率,发布/订阅 模式从三个维度实现了解耦:

  • 空间解耦: 发布者和订阅者不知道彼此的存在(例如,IP地址和端口是没有交换过程的)
  • 时间解耦: 发布者和订阅者不需要在同时间运行
  • 同步解耦: 组件之间的操作不需要在发布主题中和接收主题中而被中断

MQTT协议中的“发布/订阅”解耦特性
MQTT在空间上解耦了发布者和订阅者,意味者他们仅仅需要清楚代理服务器的IP地址和端口。另外,MQTT通过时间解耦,允许代理服务器在客户端不在线时存储消息。 存储消息必须满足两个条件: 1. 客户端必须拥有一个持久化的会话连接 2. 必须订阅一个QoS值大于0的主题

“发布/订阅”架构最重要的优点是它拥有过滤所有进来消息的能力,并且可以准确分发消息到各个订阅者, “发布/订阅”架构的一个最重要的优点是它能够过滤所有传入消息,并正确地将它们分发给订阅者,从而消除发布者和订阅者之间的存在感。

MQTT: 发布/订阅 的消息过滤特性

消息过滤是“发布/订阅”架构中的一个关键特性,它能保证订阅者仅仅收到他们感兴趣的消息。“发布/订阅”代理服务器提供了一些过滤选项,包括:基于主题的过滤,基于内容的过滤,基于类型的过滤。

选项1: “发布-订阅”架构-基于主题过滤

这是最常见的过滤选项,代理服务器可以过滤基于话题 或 主题的消息. 客户端通过订阅指定的主题标识他们感兴趣的主题, 代理服务器根据主题层级可以将消息路由到各个订阅者。主题结构是有层级关系的,层级之间用正斜杠(/)分隔,允许订阅者接收已匹配到的层级主题消息。下面是一个主题层级结构的例子:

image-2-mqtt-topic-tree-matching-challenges-best-practices-explained.png

主题层级样例

基于主题过滤的优点:

  • 简单 且 容易使用
  • 灵活的主题层级结构
  • 高效转发特定消息

基于主题过滤的缺点:

  • 订阅者和发布者需要提前约定主题层级关系
  • 仅限于基于主题层级结构筛选消息

基于主题过滤的用例:

基于主题的过滤最适合这样的用例: 消息被组织成主题,订阅者对这些主题的特定子集感兴趣。 例如,在智能家居系统中,一个订阅者仅仅感兴趣接收某个特定房间的温度变化。订阅者可以使用像"smart-home/living-room/temperature"这样的过滤表达式,代理服务器则仅仅会发送已匹配的消息到订阅者。

MQTT协议中消息过滤
MQTT 使用基于主题过滤消息机制。每个消息都包含一个主题,这个主题可以被代理服务器用于决策是否发送消息给订阅者。更多关于主题的概念,参见part 5 of MQTT Essentials. 为了处理“发布-订阅”系统中面临的挑战, MQTT协议设计了三个级别的QoS.您可以容易地指定消息成功地从客户端传递到代理服务器,或者从代理服务器传递到客户端。 但是,有可能没有人订阅特定的主题,如果这是一个问题,代理服务器必须知道如何处理这种情况。例如,HiveMQ MQTT broker 代理服务器有一种可扩展的系统来应对这种情况。您可以让代理服务器采取一些措施或者将每条消息记录到数据库中以进行历史分析。为了保持层级主题树的灵活性,非常仔细地设计主题树并为将来的用例留出空间是非常重要的。如果您遵循这些策略,MQTT对于产品准备是完美的。

选项2: “发布-订阅”架构-基于内容过滤

使用这种过滤机制,代理服务器可以基于消息的内容来过滤消息,消息内容的过滤可以使用过滤表达式。订阅者通过特定的过滤表达式来订阅标识他们感兴趣的内容,代理服务器则可以根据消息的内容将消息路由到适当的订阅者。

如何在MQTT中使用基于内容过滤的机制?
即使 MQTT 使用基于主题的消息过滤,您也可以通过使用 HiveMQ MQTT 代理和我们的自定义扩展系统来设置基于内容的过滤。

基于内容过滤的优点:

  • 提供颗粒度更细的接收消息机制
  • 允许基于消息内容的过滤比仅仅有层级结构的主题机制更好
  • 提供更复杂,更灵活的表达式

基于内容过滤的缺点:

  • 带来比基于主题过滤机制更复杂的使用和设置
  • 要求发布者在包含元数据的消息中启用筛选功能
  • 当处理大量过滤表达式时,性能可能受到影响

基于内容过滤的用例:

基于内容过滤最适合的用例: 消息没有组织成一系列主题,订阅者可以通过内容订阅特定消息子集。

例如,在一个日志应用中,订阅者仅仅感兴趣接收包含特定追踪号的数据包。订阅者可以使用像"tracking-number = '123456'"这样的过滤表达式,,并且代理服务器仅仅会发送已匹配的消息到订阅者。 

选项3: “发布-订阅”架构-基于类型过滤

使用这种过滤机制,代理服务器可根据消息的类型或类对其进行过滤。这种类型的过滤在使用面向对象语言(其中消息表示为对象)时是非常有用的。订阅者通过特定的类型或类的过滤表达式来订阅标识他们感兴趣的消息,代理服务器则可以根据消息的内容将消息路由到适当的订阅者。

基于类型过滤的优点:

  • 允许基于消息类型进行筛选,而不用关心主题或内容
  • 易于使用,特别是在使用面向对象语言时
  • 提供高度的灵活性和可扩展性

基于类型过滤的缺点:

  • 仅限于基于消息类型的筛选
  • 发布者和订阅者需要事先就消息类型的层次结构达成一致

基于类型过滤的用例:

基于类型的过滤最适合的用例: 消息被组织成类结构中,订阅者对基于这个类的特定类型或消息子集感兴趣。

例如,在金融应用程序中,订阅者可能只对接收有关股票价格的消息感兴趣。订阅者将订阅类似于“ stock-price”的消息类型,而代理服务器将只向订阅者发送此类型的消息。

这些过滤选项在决定将哪些消息发送给哪些订阅方方面提供了灵活性和颗粒度。根据不同的用例,您可以使用一个或多个这些过滤选项来确保订阅者只接收他们感兴趣的消息。

需要注意的是,发布/订阅模型可能并不适用于所有用例场景,而且有一些挑战需要思考一下,比如确保发布者和订阅者都知道哪些主题已被基于主题的过滤表达式使用了,以及处理那些没有订阅者的消息实例,最后您还需要事先了解已发布过的数据结构。

对于基于主题的过滤,发布者和订阅者都需要知道哪些主题被使用了  还有, 消息传递中,发布者不能假设有人正在监听所发送的消息。这是一个问题,因为在“发布-订阅”模型中,发布者向代理服务器发送消息,而不知道订阅者是谁,或者他们当前是否连接到代理服务器。代理服务器可以回应所有在线的订阅者,并且把分发它们所订阅的消息,但是,如果当前没有连接到代理的订阅者订阅了特定消息的主题,则该消息将不会被传递。因此,对于发布者来说,重要的是要考虑缺少保护的消息传递,并设计改进他们的系统。

MQTT 发布/订阅的可伸缩性特性

可伸缩性在“发布/订阅”架构中是至关重要的优点之一。传统的“客户端-服务器”模式限制了可伸缩性,尤其是在处理大量客户端时。因此,使用“发布/订阅”模型,代理服务器能以事件驱动的方式处理消息,能高效并行操作。意味着系统可以在不牺牲性能的情况下处理更多的并发连接。

除了事件驱动的处理之外,消息缓存和智能消息路由还有助于提高“发布/订阅”的可伸缩性。通过缓存消息,代理服务器可以快速检索消息并将其交付给订阅方,而无需进行额外的处理。另一方面,智能路由确保消息只传递给需要它们的订阅者,从而减少不必要的网络流量并进一步提高可伸缩性。

因为 MQTT 遵循“发布/订阅”架构,因此该协议具有自然的可伸缩性,这使得它非常适合于一些IoT用例。尽管有这些优势,扩展到数百万的连接仍然会对"发布/订阅"架构带来挑战。这种情况下,可以使用集群代理节点将负载分布到多个服务器上,而负载均衡器可以确保流量均匀分布。看看如何使用这个方法 HiveMQ 代理可以扩展到2亿个并发连接

现在我们已经介绍了“发布/订阅”架构的基本概念,让我们看看在IoT通信中使用它的好处。

MQTT Pub/Sub 架构在IoT和 IIoT 中的主要优势是什么?

"发布/订阅"模型提供了一些好处,使其成为了各种应用的首选。以下是使用”发布/订阅“架构的一些关键优势:

提高了可伸缩性: “发布/订阅”架构具有高度可伸缩性,适合应用程序处理大量的客户端和消息。代理服务器充当所有消息的中心集线器,允许它在不影响性能的情况下处理更多的客户端。

提高了容错能力: “发布/订阅”架构的解耦特性也提供了更好的容错能力。在传统的“客户端-服务器”模型中,如果服务器出现故障,所有已连接的客户端都会失去连接。相反,在“发布/订阅”模型中,代理服务器可以存储消息,直到客户端重新连接,确保没有消息丢失。

灵活性: “发布/订阅”架构具有灵活性,可用于各种应用程序,从低带宽、高延迟网络到高速、低延迟网络。基于“发布/订阅”架构的MQTT协议支持各种服务质量级别,为应用程序选择适的服务质量级别提供了灵活性。

“发布/订阅”架构中常见的挑战以及如何使用MQTT克服这些挑战

虽然“发布/订阅”架构提供了一些好处,比如可伸缩性、灵活性和组件的解耦,但它也带来了一些必须要解决的挑战。下面是一些使用“发布/订阅”架构最常见的挑战以及克服它们的解决方案:

  1. 消息传递: 使用“发布/订阅“的一个挑战是确保将消息传递给订阅者。在某些情况下,可能没有订阅者可以接收特定的主题,从而导致消息丢失。为了克服这一点,MQTT 提供了服务质量(QoS)级别

  2. 消息过滤: “发布/订阅”的另一个挑战是有效地过滤消息,以便每个订阅者只接收感兴趣的消息。如前所述,“发布/订阅”提供了三种过滤选项: 基于主题、基于内容和基于类型。每个选项都有其优缺点,筛选方法的选择将取决于用例。MQTT使用基于主题的消息过滤,每个消息都包含一个主题,代理服务器使用该主题来确定订阅客户端是否接收到消息

  3. 安全: 安全性是任何消息传递系统的关键方面,发布/订阅也不例外。 MQTT 支持多种安全选项,例如用户身份验证、访问控制和消息加密,以保护系统免遭未经授权的访问和数据泄露

  4. 伸缩性: “发布/订阅”架构的设计必须考虑到可伸缩性,因为在大型系统中,订阅者的数量可以呈指数级增长。MQTT支持多个代理服务器、集群和负载平衡等特性,以确保系统能够处理大量订阅者和消息

  5. 消息排序: 在“发布/订阅”系统中,消息排序可能难以维护。由于消息是异步发送的,因此很难确保订阅者以正确的顺序接收消息。然而, MQTT 提供了 QoS 级别,确保消息成功地从客户端成功的传递到代理服务器或从代理服务器成功的传递到客户端

    由于 MQTT 异步工作,任务在等待或发布消息时是不会被阻塞的。大多数客户端库基于回调或类似的模型,使得消息流通常是异步的。在某些用例中,同步是需要的,也是可能的,而且一些库具有同步 API 来等待特定的消息。

  6. 实时性: 在某些用例中,实时约束非常关键,发布/订阅架构可能不是最佳选择。例如,如果低延迟是必不可少的,请求/响应架构可能是更好的选择。

您可以通过仔细的设计和实现来解决使用“发布/订阅”的挑战。通过理解这些挑战并有效利用 MQTT 的特性,开发人员可以构建可伸缩、安全和高效的消息传递系统。

MQTT 与 消息队列

关于MQTT的名称和协议是消息队列实现的,存在很多混淆。我们将试图阐明这个话题并解释其中的差异。在 MQTT基础的第1部分中,我们提到了 MQTT是指IBM的MQ系列产品,与“消息队列”没有任何关系。无论名称来自何处,了解MQTT和传统消息队列之间的区别都很有用:

消息队列存储消息,直到消息被使消费  使用消息队列时,每个传入消息都存储在队列中,直到客户端(通常称为消费者)消费它们。如果没有客户端消费该消息,则该消息将停留在队列中并等待被使用。在消息队列中,消息不可能不被任何客户端处理,如果没有人订阅主题,那么在MQTT中就是如此。 在消息队列中,任何客户端都不可能不处理消息,就像在MQTT中一样,如果没有人订阅主题.

一个消息只能被一个客户端消费  另一个很大的区别是,在传统的消息队列中,消息只能由一个消费者处理,负载分布在队列的所有使用者之间。在MQTT协议中,行为完全相反:订阅主题的每个订阅者都会获得消息。

队列已命名,就必须显式创建  队列比主题严格得多,在使用队列之前,必须使用单独的命令显式创建队列。只有在创建并命名队列之后,才能发布或使用消息。相比之下,MQTT主题非常灵活,可以动态创建。如果你能想到我们所忽略的其他差异,我们很乐意在评论中听到你的意见。

总结

总之,“发布/订阅"架构提供了一种灵活的、可伸缩的方式来构建能够处理许多连接的客户端的分布式系统。MQTT的轻量级和高效的“发布/订阅”消息特性帮助它在IoT、移动和其他分布式应用程序中得到广泛采用。

使用MQTT协议,架构师和公司都可以在在各种真实场景中构建可靠和高效地数据通信系统。MQTT通过空间和时间、异步消息传递、基于主题的过滤和服务质量(Quality of Service,QoS)级别实现了解耦,它提供了一组健壮的特性来帮助开发人员克服构建分布式系统的挑战。总的来说,“发布/订阅”架构和 MQTT协议对于希望构建高效和可伸缩的分布式系统的开发人员来说是非常有价值的工具。