RabbitMQ

一、RabbitMQ基本架构

  1. 生产者 (Producer)
  2. 交换机 (Exchange) :直接交换机(direct),扇出交换机(fanout),主题交换机(topic),消息头交换机(headers)
  3. 消息队列 (Queue)
  4. 消费者 (Consumer)
  5. 路由键 (RoutingKey) :消息头的一个属性,用于标记消息的路由规则,决定了交换机的转发路径。最大长度255 字节。
  6. 信道 (Channel):多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接上的虚拟连接。生产者通过和交换机建立信道来发送消息,消费者也需要通过和队列建立信道来获取消息。对于操作系统来说建立和销毁TCP连接都是比较昂贵的开销,引入了信道的概念,以复用一条TCP连接。也就说,一个TCP 被多个线程共享,每个线程对应一个信道,每个信道都有唯一的ID,保证了信道的私有性

交换机的mandatory属性 为 true 时:如果交换机无法根据自身类型和路由键找到一个符合条件的队列,则会将该消息返回给生产者;为 false 时:如果交换机无法根据自身类型和路由键找到一个符合条件的队列,则会直接丢弃该消息。

二、交换机

  1. 直接交换机规则:当消息的路由键完全匹配队列绑定到交换机配置的路由键时,才会将消息转发到该队列。
  2. 扇出交换机规则:把所有发送到该交换机的消息转发到与该交换机绑定的所有消息队列中,与路由键,绑定键无关。
  3. 主题交换机规则:当消息的路由键正则匹配队列绑定到交换机配置的路由键时,才会将消息转发到该队列。
  • 绑定键中可以存在两种特殊字符*与#,用于正则模糊匹配: 只能匹配一个单词;# 可以匹配0个或者多个单词。ps: *当队列绑定键设置为#时,将接收所有来自交换机的消息,忽略路由键,就像fanout交换机一样。当绑定键中不使用和#时,topic交换机和direct交换机使用效果一样。*
  1. 消息头交换机规则:根据消息的自定义消息头属性(headers)进行匹配路由。和路由键与绑定键无关。

三、生产者确认

  1. 事务机制
  • 当生产者向RabbitMQ发送消息时,如果事务提交成功,则消息一定已到达RabbitMQ。如果在事务提交和执行之前,由于RabbitMQ的异常崩溃或其他原因引发异常,则此时我们可以捕获该异常并实现事务回滚。ps:事务会严重影响RabbitMQ的性能。
  • 生产者在消息发送后将进入阻塞发状态,等待RabbitMQ的响应,只有获取到响应后才可以继续发送下一条消息。
  1. 发布者确认机制
  • 生产者可以将信道设置为确认(confirm)模式。一旦信道进入确认模式,信道上发布的所有消息都将被分配一个唯一的ID(从1开始)。当消息被传递到所有匹配的队列时,RabbitMQ将向生产者发送确认(Ack,包括消息ID),这样生产者便知道消息已正确到达。如果消息和队列是持久化类型的,则在消息写入磁盘后发送确认消息。RabbitMQ给生产者发送的确认消息中包含确认消息的序列号。此外,RabbitMQ还可以在Ack方法中设置multiple参数,以指示此序列号之前的所有消息都已被处理。
  • 发送方确认机制是异步的。消息发布后,生产者应用程序可以在等待信道返回确认的同时继续发送下一条消息。当消息最终被确认时,生产者应用程序可以通过回调方法处理确认消息。
  • 在确认模式下,所有发送的消息只会被Ack或Nack一次,并且不会有消息同时被Ack和Nack的情况,但RabbitMQ不保证消息的确认速度。
  • 生产者确认机制的缺点是无法回滚,一旦服务器崩溃,生产者无法得到确认信息,生产者本身其实也不知道该消息是否已经被持久化,只有继续重发来保证消息不丢失,但是如果原先已经持久化的消息,并不会被回滚,这样队列中就会存在两条相同的消息,系统需要支持去重。

四、 消息持久化(Message durability)

在AMQP 0-9-1中,队列可以声明为持久或临时的。持久队列的元数据存储在磁盘上,而临时队列的元数据尽可能存储在内存中。

  1. 默认情况下,消息不是持久的,当RabbitMQ退出或崩溃时,它会忘记队列和消息,除非你告诉它不要这样做。需要做两件事来确保消息不会丢失:需要将队列和消息都标记为持久

ps:将消息标记为持久并不能完全保证消息不会丢失。尽管它告诉RabbitMQ将消息保存到磁盘,但还是存在RabbitMQ接受消息但尚未保存消息的短时间窗口。此外,RabbitMQ不会对每条消息执行fsync(2)–它可能只是保存到缓存中,而不是真正写入磁盘。持久性保证性并不强,但对于我们的简单任务队列来说已经足够了。如果需要更强有力的保证,那么你可以使用发布确认

五、工作队列消息分发机制

一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致消费速率跟不上消息生产速率。因此如果一个生产者对应一个消费者的话,很容易导致很多消息堆积在队列里。这时,就得使用工作队列了:一个队列有多个消费者同时消费数据。

  1. 轮询分发(Round-robin dispatching)

默认情况下,RabbitMQ将按顺序将每条消息发送给下一个消费者。平均而言,每个消费者都会收到相同数量的消息。这种分发消息的方式称为轮询。

  1. 公平分发(Fair dispatch)

消费者设置每次从队列里取一条数据,并且关闭自动回复机制,每次取完一条数据后,手动回复并继续取下一条数据。与轮询分发不同的是,当每个消费都设置了每次只会从队列取一条数据时,并且关闭自动应答,在每次处理完数据后手动给队列发送确认收到数据。