分布式消息通信队列——rabbitmq

对于传统的Linux服务中,各模块间通信我们可以通过进程间通信、线程间通信的机制实现。但对于分布式系统中,其架构中含有多个组件、多个子系统,而且各组件/子系统可能是分布在不同节点上,因此要如何实现它们之间的通信呢?

第一种方式:IPC
IPC通信的缺点是其各模块耦合性太大,不适合扩展
第二种方式:Socket
socket是一种常用的通信方式,是开发中常用的一种手段,但它需要维持链接不中断,而且发送者/接收者耦合度大,并且需要考虑接收者优先级等问题。

因此分布式消息通信机制在分布式系统中是一种常用的方式,其协议AMQP,对于分布式异步通信是一种很好的方式。本文以rabbtmq为例。rabbitmq也是作为OpenStack云平台中,各组件中间通信的中间件,实现OpenStack各模块间的异步通信。

推荐一个rabbitmq模拟学习的网址:tryrabbitmq

1. rabbitmq简介

1. RabbitMQ Server的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。
2. Client A & B: 也叫Producer,数据的发送方。一个Message有两个部分:payload(有效载荷)和label(标签)。payload顾名思义就是传输的数据。label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。
3. Client 1,2,3:也叫Consumer,数据的接收方。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的。

2. rabbitmq的通信方式:

Producter和consumer消息传递方式:exchanges, queues and bindings。
Exchanges : are where producers publish their messages.
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.

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

如果message有订阅者(consumer subscribe),当message到queue,会立即被发送给consumer,当consumer正确接收后,queue删掉message;
如果message没有订阅者,则message到达queue后,会被转到cache,而不会被丢弃。

正确收到:consumer返回ack

Consumer reject a message后,rabbitMQ server两种处理方法:
1、 Reject后rabbitMQ server发给下一个consumer
2、 rabbitMQ server删掉message

prudocer : 消息的发送者
queue(broker): 在应用之间传输的message实际上在queue中。其本质上是一块大内存。是producer把message发给queue,然后consumer从queue中取message
consumer: 等待message的应用

producer、consumer和broker不必一定在同一host上。
如果producer把message发给一个不存在的queue,rabbitMQ只会丢掉消息(drop message)

routing_key参数:queue的名字,指定message经过exchange后应该发给哪个queue。

如果有多个consumer/worker时,producer发出来的message将会被consumer轮询消费。

Q: 如果consumer/worker对message处理要有一定的时间,在这段时间内,message还没处理完,但consumer/worker挂掉了或者被干掉了,会发生什么?
A:
1. 没有ack的情况下:consumer不返回ack
在当前的rabbitMQ代码版本(version 0.11.0)中,当message被发送给consumer后,马上被标记为deletion。当worker被干掉后,这个正在处理的message会丢失,同时所有发给这个worker的、还没出来的的message都会丢掉。
2. 有ack情况下:consumer如果正常处理message,则返回ack
如果没有收到ack,则表示consumer没完全正确处理message,rabbitMQ会重新re-queue改消息,再将其发给其他consumer。(timeout?)



声明exchange、queue等时,使用channel.exchange_declare()或channel.queue_declare()方法,参数解析:
1. durable:持久的,即当rabbitMQ重启之后,是否会丢失,当exchange或queue声明时加入durable=true,则rabbitMQ重启后,exchange和queue仍存在。Eg:channel.exchange_declare(exchange='web', durable=True)
2. exclusive:当exclusive=true时,consumer连接关闭时,queue可检测到。Eg:result = channel.queue_declare(exclusive=True),没有指定queue名字,系统将自动随机生成一个名字。

exchange:一边从producer接收message,然后另一边将message发给queue。Exchange需要知道应该对message做什么处理:是发给某个queue,或是发给多个queue,亦或是丢弃message,exchange type定义了这些规则。
Exchange type的类型有:direct、topic、headers和fanout
• fanout: 广播,所有订阅到这个exchange的queue都会接收到message。
• direct: 可以根据routing_key定向选择message。在binding时,通过加入routing_key参数:channel.queue_bind(routing_key=XXX),然后发布message时,在channal.basic_publish(routing_key=XXX)来实现两者对应。
• topic: 也是通过匹配routing_key来选择queue。Topic的routing_key包含一系列关键词,每个关键词用“.”分开,有两个特性:*代表一个词,#代表零个或多个词。如word1.word2.word3
如果只有#,则topic变成fanout。
如果没有*和#,则topic就是direct。
 

ref:

消息队列在分布式系统中的应用 https://blog.csdn.net/Jmilk/article/details/78642316
快速入门分布式消息队列之 RabbitMQ(1) https://blog.csdn.net/jmilk/article/details/78705281
快速入门分布式消息队列之 RabbitMQ(2) https://blog.csdn.net/Jmilk/article/details/78712632
快速入门分布式消息队列之 RabbitMQ(3) https://blog.csdn.net/jmilk/article/details/78767168 

猜你喜欢

转载自blog.csdn.net/ksj367043706/article/details/89764294