简介
消息队列中间件(Message Queue Middleware,简称为MQ)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。
目前开源的消息中间件有很多,比较主流的有RabbitMQ、Kafka、ActiveMQ、RocketMQ等。面向消息的中间件提供了以松散耦合的灵活方式集成应用程序的一种机制。
消息中间件适用于需要可靠的数据传送的分布式环境。采用消息中间件的系统中不同的对象之间通过传递消息来激活对方的事件,以完成相应的操作。消息中间件常被用来屏蔽各种平台及协议之间的特性,实现应用程序之间的协同,其优点在于能够在客户和服务器之间提供同步和异步的连接,并且在任何时刻都可以将消息进行传送或者存储转发。
消息中间件的用途可以概括如下:
- 解耦
- 冗余
- 削峰
- 可恢复性
- 顺序保证
- 缓冲
- 异步通信
RabbitMQ是采用Erlang语言实现AMQP (Advanced Message Queuing Protocol,高级消息队列协议)的消息中间件,在易用性、扩展性、可靠性和高可用性等方面有着卓越表现。
安装
手动安装RabbitMQ较为繁琐,这里提供一种简单的基于Docker的安装方式:
docker run -d --name rabbitmq --hostname my-rabbitmq -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin [拉取的RabbitMQ镜像id]
核心概念
RabbitMQ整体上是一个生产者与消费者模型,主要负责接收、存储和转发消息。从计算机术语层面来说,RabbitMQ模型更像是一种交换机模型。RabbitMQ的整体模型架构如下图所示:
Producer:生产者
生产者创建消息,然后发布到RabbitMQ中。消息一般可以包含2个部分:消息体和标签。在实际应用中,消息体一般是一个带有业务逻辑结构的数据,比如一个JSON 字符串。消息的标签用来表述这条消息,比如一个交换器的名称和一个路由键。生产者把消息交由RabbitMQ,RabbitMQ之后会根据标签把消息发送给感兴趣的消费者(Consumer)。
Consumer:消费者
消费者连接到RabbitMQ服务器,并订阅到队列上。在消息路由的过程中,消息的标签会丢弃,存入到队列中的消息只有消息体,消费者也只会消费到消息体。
Broker:服务节点
对于RabbitMQ来说,一个RabbitMQ Broker可以简单地看作一个RabbitMQ服务节点,或者RabbitMQ服务实例。大多数情况下也可以将一个RabbitMQ Broker看作一台RabbitMQ服务器。
Queue:队列
RabbitMQ的生产者生产消息并最终投递到队列中,消费者可以从队列中获取消息并消费。多个消费者可以订阅同一个队列,这时队列中的消息默认会被平均分摊(Round-Robin,即轮询)给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,RabbitMQ不支持队列层面的广播消费。
Exchange:交换器
生产者并不会直接将消息发送到队列,而是将消息发送到交换器,由交换器将消息路由到一个或者多个队列中。如果路由不到,会根据配置返回给生产者或者直接丢弃。交换器有四种类型,不同的类型有不同的路由策略。
BindingKey:绑定键
RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键,这样RabbitMQ就知道如何正确地将消息路由到队列了。
RoutingKey:路由键
生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定这个消息的路由规则,而这个RoutingKey需要与交换器类型和绑定键联合使用才能最终生效。交换器会根据自身的类型对路由键和绑定键进行匹配,匹配成功则将消息转发到对应的队列中。
Connection:连接
无论是生产者还是消费者,都需要和RabbitMQ Broker建立TCP连接,这个连接就是Connection。
Channel:信道
一旦TCP连接建立起来,客户端就可以创建一个AMQP信道,每个信道都会被指派一个唯一的ID。信道是建立在Connection之上的虚拟连接,RabbitMQ处理的每条AMQP指令都是通过信道完成的。
注:在多线程应用场景下,每个线程对应一条信道,复用同一条连接,这样可以提高性能,同时也便于管理。
交换器类型
RabbitMQ常用的交换器类型有fanout、direct、topic、headers这四种。
fanout
fanout类型交换器会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中,会屏蔽掉路由键、绑定键的作用。
direct
direct类型交换器会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。
topic
topic类型的交换器在匹配规则上进行了扩展,它与direct类型的交换器相似,也是将消息路由到 BindingKey和RoutingKey相匹配的队列中,但这里的匹配规则有些不同,它有下面这些约定:
- RoutingKey为一个点号“.”分隔的字符串,如“com.rabbitmq.client” 。
- BindingKey和RoutingKey一样也是点号“.”分隔的字符串。
- BindingKey中可以存在两种特殊字符串“*”和“#”,用于做模糊匹配,其中“#”用于匹配一个单词,“#”用于匹配一个或多个单词(可以是零个)。
headers
headers类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时制定一组键值对,当发送消息到交换器时,RabbitMQ会获取到该消息的headers,对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers类型的交换器性能很差,而且也不实用,基本上不会看到它的存在。
运转流程
现在总结一下RabbitMQ的整个使用流程。首先是生产者:
- 生产者连接到RabbitMQ Broker,建立一个连接,开启一个信道。
- 生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等。
- 生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等。
- 生产者通过路由键将交换器和队列绑定起来。
- 生产者发送消息至RabbitMQ Broker,其中包含路由键、交换器等信息。
- 相应的交换器根据接收到的路由键查找相匹配的队列。
- 如果找到,则将从生产者发送过来的消息存入相应的队列中。
- 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者。
- 关闭信道。
- 关闭连接。
对于消费者:
- 消费者连接到RabbitMQ Broker,建立一个连接,开启一个信道。
- 消费者向RabbitMQ Broker请求消费相应队列中的消息(推模式),可能会设置相应的回调函数,以及做一些准备工作。
- 等待RabbitMQ Broker回应并投递相应队列中的消息,消费者接收消息。
- 消费者确认(ack)接收到的消息。
- RabbitMQ从队列中删除相应已经被确认的消息。
- 关闭信道。
- 关闭连接。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。