RabbitMQ的架构、交换机机制和ACK机制

来源:互联网 发布:网络个体名称大全 编辑:程序博客网 时间:2024/06/05 18:49
RabbitMQ 


  1. RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。
  1. RabbitMQ 即一个消息队列,_主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用。_
  2. RabbitMQ使用的是AMQP协议,它是一种二进制协议。默认启动端口 5672。

RabbitMQ 的架构



  • RabbitMQ Server: 也叫broker server,它不是运送食物的卡车,而是一种传输服务。
    1. RabbitMQ isn’t a food truck, it’s a delivery service。 他的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。
    2. 但是这个保证也不是100%的保证,但是对于普通的应用来说这已经足够了。
    3. 当然对于商业系统来说,可以再做一层数据一致性的guard,就可以彻底保证系统的一致性了。


    
  • Client A & B 也叫Producer,数据的发送方。
    1. create messages and publish (send) them to a broker server (RabbitMQ)。一个Message有两个部分:payload(有效载荷)和label(标签)。
    2. payload顾名思义就是传输的数据。label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。
    3. AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。

    
  • Client 1,2,3:也叫Consumer,数据的接收方。
    1. Consumers attach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。
    2. 在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的。就是协议本身不支持。
    3. 但是当然了如果Producer发送的payload包含了Producer的信息就另当别论了。

 
对于一个数据从Producer到Consumer的正确传递,还有几个个概念需要明确:
其中比较重要的概念有 4 个,分别为:虚拟主机,交换机,队列,和绑定。
  • 虚拟主机:一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主机呢?很简单,RabbitMQ当中,_用户只能在虚拟主机的粒度进行权限控制。_因此,如果需要禁止A组访问B组的交换机/队列/绑定,必须为A和B分别创建一个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。
  • 交换机(Exchanges are where producers publish their messages.):Exchange 用于转发消息,但是它不会做存储_ ,如果没有 Queue bind 到 Exchange 的话,它会直接丢弃掉 Producer 发送过来的消息。
  • 这里有一个比较重要的概念:路由键 。消息到交换机的时候,交互机会转发到对应的队列中,那么究竟转发到哪个队列,就要根据该路由键。
  • 队列: Queues are where the messages end up and are received by consumers
  • 绑定(Bindings are how the messages get routed from the exchange to particular queues):也就是交换机需要和队列相绑定,这其中如上图所示,是多对多的关系。
    
还有几个概念是上述图中没有标明的,那就是Connection(连接),Channel(通道,频道)。

  • Connection 就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。
  • Channels 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。

那么,为什么使用Channel,而不是直接使用TCP连接?
  1. 对于OS来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,
  2. 这也限制了系统处理高并发的能力。
  3. 但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。
  4. 有实验表明,1s的数据可以Publish10K的数据包。
  5. 当然对于不同的硬件环境,不同的数据包大小这个数据肯定不一样,但是我只想说明,对于普通的Consumer或者Producer来说,这已经足够了。
  6. 如果不够用,你考虑的应该是如何细化split你的设计。

RabbitMQ 的交换机机制

什么是交换机

rabbitmq的message model实际上消息不直接发送到queue中,中间有一个exchange是做消息分发,producer甚至不知道消息发送到那个队列中去。因此,当exchange收到message时,必须准确知道该如何分发。是append到一定规则的queue,还是append到多个queue中,还是被丢弃?这些规则都是通过exchagne的4种type去定义的。

  1. The core idea in the messaging model in RabbitMQ is that the producer never sends any messages directly to a queue. 
  2. Actually, quite often the producer doesn't even know if a message will be delivered to any queue at all.
  3. Instead, the producer can only send messages to an exchange.
  4. An exchange is a very simple thing. On one side it receives messages from producers and the other side it pushes them to queues. 
  5. The exchange must know exactly what to do with a message it receives.
  6. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded.
  7. The rules for that are defined by the exchange type.

exchange是一个消息的agent,每一个虚拟的host中都有定义。它的职责是把message路由到不同的queue中。

binding

  1. exchange和queue通过routing-key关联,这两者之间的关系是就是binding。
  2. 如下图所示,X表示交换机,红色表示队列,交换机通过一个routing-key去binding一个queue,routing-key有什么作用呢?
  3. 看Direct exchange类型交换机。


Directed Exchange

  • 路由键交换机,该交换机收到消息后会把消息发送到指定routing-key的queue中。那消息交换机是怎么知道的呢?其实,producer deliver消息的时候会把routing-key add到 message header中。routing-key只是一个messgae的attribute。

  1. A direct exchange delivers messages to queues based on a message routing key. 
  2. The routing key is a message attribute added into the message header by the producer. 
  3. The routing key can be seen as an "address" that the exchange use to decide how to route the message.
  4. A message goes to the queue(s) whose binding key exactly matches the routing key of the message.

  • Default Exchange
  1. 这种是特殊的Direct Exchange,是rabbitmq内部默认的一个交换机。
  2. 该交换机的name是空字符串,所有queue都默认binding 到该交换机上。
  3. 所有binding到该交换机上的queue,routing-key都和queue的name一样。

Topic Exchange

  • 通配符交换机,exchange会把消息发送到一个或者多个满足通配符规则的routing-key的queue。
  • 其中"_"表号匹配一个word,"#"匹配多个word和路径,路径之间通过"."隔开。
  • 如满足a._.c的routing-key有a.hello.c;满足#.hello的routing-key有a.b.c.helo。

Fanout Exchange

  • 扇形交换机,该交换机会把消息发送到所有binding到该交换机上的queue。这种是publisher/subcribe模式。用来做广播最好。
  • 所有该exchagne上指定的routing-key都会被ignore掉。

  1. The fanout copies and routes a received message to all queues that are bound to it regardless of routing keys or pattern matching as with direct and topic exchanges. 
  2. Keys provided will simply be ignored.

Header Exchange

  • 设置header attribute参数类型的交换机。


RabbitMQ 的消息持久化

  • 在生产环境中,我们需要考虑万一生产者挂了,消费者挂了,或者 rabbitmq 挂了怎么样。一般来说,如果生产者挂了或者消费者挂了,其实是没有影响,因为消息就在队列里面。那么万一 rabbitmq 挂了,之前在队列里面的消息怎么办,其实可以做消息持久化,RabbitMQ 会把信息保存在磁盘上。
  • 做法是可以先从 Connection 对象中拿到一个 Channel 信道对象,然后再可以通过该对象设置 消息持久化

RabbitMQ 的生产者或者消费者断线重连

这里 Spring 有自动重连机制。

RabbitMQ 的ACK 确认机制

  • 每个Consumer可能需要一段时间才能处理完收到的数据。如果在这个过程中,Consumer出错了,异常退出了,而数据还没有处理完成,那么 非常不幸,这段数据就丢失了。因为我们采用no-ack的方式进行确认,也就是说,每次Consumer接到数据后,而不管是否处理完 成,RabbitMQ Server会立即把这个Message标记为完成,然后从queue中删除了。
  • 如果一个Consumer异常退出了,它处理的数据能够被另外的Consumer处理,这样数据在这种情况下就不会丢失了(注意是这种情况下)。
  • 为了保证数据不被丢失,RabbitMQ支持消息确认机制,即acknowledgments。
  • 为了保证数据能被正确处理而不仅仅是被Consumer收到,那么我们不能采用no-ack。而应该是在处理完数据后发送ack。
  • 在处理数据后发送的ack,就是告诉RabbitMQ数据已经被接收,处理完成,RabbitMQ可以去安全的删除它了。
  • 如果Consumer退出了但是没有发送ack,那么RabbitMQ就会把这个Message发送到下一个Consumer。
  • 这样就保证了在Consumer异常退出的情况下数据也不会丢失。

RabbitMQ 总结

  1. RabbitMQ 作用:异步,解耦,缓冲,消息分发。
  2. RabbitMQ 主要分为3个部分,生产者,交换机和队列,消费者。
  3. 需要注意消息持久化,目的为了防止 RabbitMQ 宕机;考虑 ACK 机制,目的为了如果消费者对消息的处理失败了,那么后续要如何处理。

参考来源: http://blog.csdn.net/anzhsoft/article/details/19563091
参考来源: https://github.com/401Studio/WeekLearn/issues/2
原创粉丝点击