MQTT Part 2 发布和订阅

本文翻译自http://www.hivemq.com/blog/mqtt-essentials-part2-publish-subscribe

未经允许,不得转载

发布/订阅模式

发布/订阅(pub/sub)模式是传统的客户端-服务器模式的一种替代方案。我们将发送数据的客户端称之为发布者,将接收数据的客户端称为订阅者,发布/订阅模式将这些客户端进行解耦。这意味着发布者和订阅者互相不知道对方的存在,在其之间存在一个第三方组件,我们称之为中间人(broker),发布者和订阅者只与中间人进行通信。中间人可以过滤收到的信息,并对其进行相应的分发。下面让我们对其进行更进一步的了解,这只是发布/订阅模式的基础部分,稍后我们将探讨更多细节。


MQTT Part 2 发布和订阅_第1张图片

正如上面提到的,发布/订阅模式可以将发布者和订阅者在多个维度进行解耦:

  • 空间解耦:发布者和订阅者不需要互相知道对方的存在,例如对方的ip地址,端口号等。
  • 时间解耦:发布者和订阅者不需要同时运行。
  • 同步解耦:在发布和订阅消息时,双方的运作无需中断。

总之,发布/订阅模式解耦了发布者和订阅者,通过消息过滤使得某个客户端只接受某个消息得以实现。解耦从三个维度展开:空间上、时间上和同步上。

扩展性

相较于传统的客户端-服务器模式,发布/订阅模式还提供了更好的扩展性。这是因为在broker上的操作可以高度并行处理。消息缓存和智能路由在提高可扩展性上起了决定性作用。但百万级的连接量对发布/订阅模式仍然是个挑战,这可以通过集群式的broker节点来实现,借助负载均衡器可以将单个的服务器的压力进行分摊。(我们会用单独的一章来介绍此内容,其目前超越了我们的讨论范围)

消息过滤

令人感兴趣的是,broker是怎样过滤消息的,如何使订阅者只接受到其感兴趣的消息?

选择1:基于主题过滤

主题是消息体的一部分,接收端通过在broker上订阅其感兴趣的主题,以获取所有关于此主题的全部消息。主题是具有分层结构的普通字符串,其允许过滤器基于有限数量的表达式进行过滤。

选择2:基于内容过滤

正如其名,基于内容过滤即broker基于特定的内容进行过滤。broker通过查询消息来提供给订阅者其感兴趣的消息内容。这种方式的一大弊端就是消息内容必须被预知并且不能被加密,也不能被轻易改动。

选择3:基于类型过滤

当采用面向对象语言时,基于消息或事件的类型(type)或类(class)进行过滤是一种常见方案。在这种情况下,订阅者可以监听所有来自此类或其子类的消息。

当然了,发布/订阅模式也不是万能的,在使用它之前,还要考虑一些事情。解耦发布者和订阅者是发布/订阅模式的关键,这也为其带来一些难点。你必须预知所发布消息的结构。在基于主题过滤的情况下,发布者和订阅者需要知道正确的主题。在分发消息方面,发布者并不知道有谁在接受其所发布的消息,所以可能某些消息永远都不会有订阅者。

MQTT

现在我们学习了发布/订阅模式的基本内容,但MQTT与其有什么关系?MQTT采用的即是发布/订阅模式,实现了我们上文提到的所有方面,就看你怎么使用它了。MQTT也解耦了发布者和订阅者,所以我们只需要知道broker的主机IP地址和端口号,即可实现发布订阅消息。它同样在时间上实现了解耦,但这是种低效运行方案,因为大部分使用场景都需要近乎实时地分发消息。当然,broker也可以在客户端不在线时缓存消息。(这需要满足两个前提条件:客户端曾连接过一次,并且会话是持久的,而且其以高于0的服务质量级别的方式订阅过相应的主题)。MQTT同样可以在同步上进行解耦,大部分客户端库都是异步实现的,采用回调或类似机制。所以其在发布和订阅消息时不会干扰其他任务。但某些情况下采用同步方案效果也不错,所以某些库也支持同步API来等待消息。但是通常情况下,数据流都是异步的。另一个需要提及的重点是MQTT在客户端实现起来非常容易。不同的发布/订阅系统的broker有不同的实现逻辑,但客户端的解决方案都一样,只需要导入客户端的库文件即可实现,这是非常适合小型的资源受限的设备使用的轻量级协议。

MQTT采用基于主题的消息过滤方式,所以每个消息都需要包含一个主题以便于broker识别,进而也决定了订阅者是否能收到这条消息。HiveMQ broker也可以通过自定义插件来实现基于内容的过滤方式。

为了更好的使用发布/订阅模式,MQTT定义了一个服务质量(QoS)级别,借此可以很容易的指定broker和客户端消息收发成功率级别。对于某些主题无人订阅的情况,broker如何处理这种情况可以决定这是否是一个问题。例如HiveMQ broker有一个插件系统,能够识别这种情况并加以处理,或者仅将其写入数据库日志以供历史分析。为了规避主题变动的风险,小心设计主题树,并为以后的扩展留足空间十分重要。如果你采用了这种策略,MQTT将会是完美的产品解决方案。

和消息队列的区别

MQTT存在一些让人容易混淆的地方,例如他的名字以及它是否采用的是消息队列的方式。现在让我们将其解释清楚,上一章节我们提到过MQTT的名字和消息队列(message queue)没有任何关系,但是除却名字不提,MQTT和传统的消息队列模式有什么不一样呢?

消息队列会存储消息直到其被消费
当使用消息队列时,每一个入队消息都会被存储起来,直至其被其他客户端取出(我们常称之为消费)。否则,消息将会被卡在消息队列中一直等待着被消费。消息不能不被任何客户端处理,这有点像在MQTT中无人订阅的一个主题。

一个消息只会被一个客户端消费
另一个较大的不同是传统的消息队列中的一个消息只能被一个客户端消费,所有的客户端以分布式的方式处理同一个消息队列。在MQTT中正好相反,每一个订阅者都可以收到其订阅的主题消息。

队列需要被明确地命名
一个队列比一个主题要固定的多,在使用队列之前,必须使用一个特定的命令来创建队列,只有这样它才能发布和消费消息。而MQTT的主题要灵活的多。

你可能感兴趣的:(MQTT Part 2 发布和订阅)