九浅一深之RabbitMQ

时间:2019-10-04 14:48来源:编程技术
RabbitMQ(MQ 为 MessageQueue)是一个消息队列, 主要是用来实现应用程序的异步和解耦,同时起到消息缓冲、消息分发作用 RabbitMQ是一个开源的AMQP实现:AMQP,即Advanced Message QueuingProtocol,
  • RabbitMQ(MQ 为 MessageQueue) 是一个消息队列,主要是用来实现应用程序的异步和解耦,同时起到消息缓冲、消息分发作用

RabbitMQ是一个开源的AMQP实现:AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

消息队列

  • 消息是指应用间传送的数据,可以为字符文本、潜入对象
  • 消息队列(Message Queue)是一种应用的通信方式,消息发送后可立即返回,由消息系统来确保可靠的传递,消息发布者只管消息发布到 MQ 中而不用管谁来取,消息消费者只管从 MQ 中取消息而不管是谁发布,这样发布者和消费者都不用知道对方的存在

为何用消息队列

  • 消息队列是一种应用程序异步协作机制
  • 以订单系统为例:用户点击按钮之后的业务逻辑可能包括:扣减库存、生成相应数据、发送短信通知
  • 在业务初期这些逻辑可能放在一起同步执行,随着业务发展订单量增大,需要提升系统服务的性能,这时可以将一些不需立即生效的操作拆分出来异步执行,如发送短信通知,这种场景下就可以使用 MQ
  • 在下单的主流程(扣减库存、生成相应单据)完成之后发送一条消息到 MQ 让主流程快速完结,而由另外的单独线程拉取 MQ 的消息(或由 MQ 推送消息),当发现 MQ 中有发红包或发短信之类的消息时,执行相应的业务逻辑
  • RabbitMQ 最初起源于金融系统,用于在分布式系统中存储转发消息,它是 AMQP 协议的开源实现
  • AMQP:Advanced Message Queue它是应用层协议的一个开放标准,为面向消息得中间件设计,基于此协议的客户端与消息中间件可传递消息,并且不受产品、开发语言等条件限制
  • 可靠性:RabbitMQ 通过一些机制来保证可靠性,如持久化、传输确认、发布确认
  • 灵活的路由:在消息进入队列之前,通过 Exchange 来路由消息,RabbitMQ 提供了一些内置得 Exchange 实现,也可以自定义
  • 消息集群:多个 RabbitMQ 可以组成一个集群
  • 高可用:队列可以在集群中的机器上进行镜像,某些节点出现问题的情况下仍然可用
  • 多种协议:RabbitMQ 支持多种消息队列协议,如 STOMP、MQTT
  • 管理界面:RabbitMQ 提供了一个易用的用户界面
  • 跟踪机制:RabbitMQ 提供了消息跟踪机制可以跟踪消息异常
  • 插件机制:RabbitMQ 提供了许多插件可以进行扩展

ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。ConnectionFactory为Connection的制造工厂。 Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。

消息模型

  • 消费者订阅某个队列,生产者创建消息,然后发布到队列中,最后消息发送到监听的消费者

    图片 1

图片 2

RabbitMQ 基本概念

图片 3

  • Message:消息由消息头和消息体组成,消息体是不透明的,而消息头由一系列可选属性组成,包括 routing-key、priority(相对其它消息的优先权)
    • 持久化:消息在 RabbitMQ 重启后仍然存在
  • Publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序
  • Exchange:交换器,用来接收生产者发送的消息并将消息路由给服务器中的队列
    • 持久化:交换器在 RabbitMQ 重启后仍然存在
    • 自动删除:没有任何队列绑定交换机时,交换机会自动删除
  • Binding:绑定,用于将消息队列和交换器关联,例如基于路由键将交换器和消息队列连接起来的路由规则
  • Queue:消息队列,用来保存消息直到发送给消费者,是消息得容器,也是消息得终点,一个消息可以投入一个或多个队列,消息一直在队列里面,等待消费者将其取走
    • 持久化:队列在 RabbitMQ 重启后仍然存在,但是队列里面的消息是否保存,还是要看消息是否设置为持久化
  • Connection:网络连接,比如一个 TCP 连接
  • Channel:信道,双向数据流通道,AMQP 命令都是通过信道发送出去的,不管是发布消息、订阅消息、还是接收消息都是通过信道完成
  • Consumer:消息的消费者,表示一个从消息队列中取得消息得客户端应用程序
  • Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象,虚拟主机是共享相同得身份认证和加密环境的独立服务器域,每个 vhost 本质是就是一个 mini 版得 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制
  • Broker:表示消息队列服务器的实体

RabbitMQ

AMQP 中的消息路由

  • AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列

    图片 4

Message

消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

Exchange 类型

  • Exchange 分发消息时根据类型不同分发策略也有区别,共四种类型:direct、fanout、topic、headers
  • headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了

图片 5

  • 消息中的路由键如果和 Binding 中的 binding key 一致,交换器就将消息发送到对应队列中
  • 它是完全匹配、单播模式,如某路由键为 "dog" 则它只转发 routing key 标记为 "dog" 的消息,不会转发 "dog.puppy"、"dog.guard" 等等

图片 6

  • 每个发到 fanout 类型的交换器消息都会分到所有绑定的队列上,fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定得所有队列上
  • 像子网广播,每台子网内得主机都获得了一份复制的消息,fanout 类型转发消息是最快的

图片 7

  • topic 交换器通过模式匹配分配消息得路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上
  • 它将路由键和绑定键得字符串切分成单词,这些单词之间用点隔开,可用两个通配符:符号 #(匹配0个或多个单词) 和符号 ""

Publisher

消息的生产者,也是一个向交换器发布消息的客户端应用程序。

Exchange

交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。

Binding

绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。

Queue

消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。

Connection

网络连接,比如一个TCP连接。

Channel

信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内地虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。

Consumer

消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。

Virtual Host

虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

Broker

表示消息队列服务器实体。

AMQP 中的消息路由

AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange 和 Binding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。

图片 8

Exchange 类型

Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了

direct

图片 9

消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。它是完全匹配、单播的模式。

fanout

图片 10

每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。

topic

图片 11

图片 12

  • routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
  • binding key与routing key一样也是句点号“. ”分隔的字符串
  • binding key中可以存在两种特殊字符''与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)

header

headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。 在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

RPC

MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。 但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。

图片 13

RabbitMQ 中实现RPC 的机制是:

  • 客户端发送请求(消息)时,在消息的属性(MessageProperties ,在AMQP 协议中定义了14中properties ,这些属性会随着消息一起发送)中设置两个值replyTo (一个Queue 名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue 中)和correlationId (此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)
  • 服务器端收到消息并处理
  • 服务器端处理完消息后,将生成一条应答消息到replyTo 指定的Queue ,同时带上correlationId 属性
  • 客户端之前已订阅replyTo 指定的Queue ,从中收到服务器的应答消息后,根据其中的correlationId 属性分析哪条请求被执行了,根据执行结果进行后续业务处理

RabbitMQ 选型和对比

  • 从社区活跃度
    按照目前网络上的资料,RabbitMQ 、activeM 、ZeroMQ 三者中,综合来看,RabbitMQ 是首选。
  • 持久化消息比较
    ZeroMq 不支持,ActiveMq 和RabbitMq 都支持。持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消息不会丢失的机制。
  • 综合技术实现
    可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等等。
    RabbitMq / Kafka 最好,ActiveMq 次之,ZeroMq 最差。当然ZeroMq 也可以做到,不过自己必须手动写代码实现,代码量不小。尤其是可靠性中的:持久性、投递确认、发布者证实和高可用性。
  • 高并发
    毋庸置疑,RabbitMQ 最高,原因是它的实现语言是天生具备高并发高可用的erlang 语言。
  • 比较关注的比较, RabbitMQ 和 Kafka
    RabbitMq 比Kafka 成熟,在可用性上,稳定性上,可靠性上, RabbitMq 胜于 Kafka (理论上)。

另外,Kafka 的定位主要在日志等方面, 因为Kafka 设计的初衷就是处理日志的,可以看做是一个日志(消息)系统一个重要组件,针对性很强,所以 如果业务方面还是建议选择 RabbitMq 。
还有就是,Kafka 的性能(吞吐量、TPS )比RabbitMq 要高出来很多。

原文:消息队列之 RabbitMQ 、 我为什么要选择RabbitMQ

编辑:编程技术 本文来源:九浅一深之RabbitMQ

关键词: