一.RabbitMQ简介
RabbitMQ是一个消息中间件。原理是简单的,就是负责消息(二进制块数据)的接收,存储和发送。
RabbitMQ的工作流程大致如下图:
工作流程大致如下:
左边的Client向右边的Client发送消息,流程:
1, 获取Conection
2, 获取Channel
3, 定义Exchange,Queue
4, 使用一个RoutingKey将Queue Binding到一个Exchange上
5, 通过指定一个Exchange和一个RoutingKey来将消息发送到对应的Queue上,
6, 接收方在接收时也是获取connection,接着获取channel,然后指定一个Queue直接到它关心的Queue上取消息,它对exchange,routingKey及如何binding都不关心,到对应的Queue上去取消息就OK了。
具体各部分如下:
发送(Sending):
1.建立一个跟RabbitMQ服务器的连接:
connection= pika.BlockingConnection(pika.ConnectionParameters( 'localhost'))
channel = connection.channel()
2.创建一个队列:
channel.queue_declare(queue='hello')
hello:为队列的名字。
3.指定发送消息的一些参数:
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print" [x] Sent 'Hello World!'"
exchage:信息交换机,改成为空;
routing_key:指定队列,该处为hello。
body:消息体,该处为hello World!。
4关闭连接:
当消息已经被传到队列后,关闭连接,释放资源
connection.close()
接收(Receiving)
1.建立一个跟RabbitMQ服务器的连接:
connection= pika.BlockingConnection(pika.ConnectionParameters( 'localhost'))
channel = connection.channel()
2.创建一个队列:
channel.queue_declare(queue='hello')
hello:为队列的名字。
3.消息的接收:
defcallback(ch, method, properties, body):
print " [x] Received%r" % (body,)
4.通知RabbitMQ:
通知RabbitMQ Server callback将从hello队列接收消息。
channel.basic_consume(callback,
queue='hello',
no_ack=True)
no_ack:消息确认参数,true为不需要确认消息。
5等待接收消息:
print' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()
二.工作队列(Work Queues)
Work Queues背后的思想是避免资源密集性的任务立即执行跟必须等待任务的完成。取而代之我们可以稍后再调度任务。我们把任务压缩为一个消息,并且发送给队列。一个运行在后台的worker将弹出任务并且执行任务。当有许多的worker在运行时,他们将共同分担这些消息。
1.循环调度 (Round-robin dispatching)
使用任务队列的优势之一是能够让接收平行工作。如果我们有很多消息需要接收处理,那么我们可以添加多个接收器,接收器可以平行工作。
工作情景:当p发送1,2,3,4,5到消息队列,C1可能接收到1,4,5,而C2接收到2,3.
测试例子如下:
运行2个worker.py,然后运行5次new_task.py 带不同参数,结果如下:
信息发送器:
[root@localhost python]# python new_task.py 1........
[x] Sent '1........'
/usr/lib/python2.4/site-packages/pika-0.9.6_pre0-py2.4.egg/pika/canection.CloseOk"
[root@localhost python]# python new_task.py 2........
[x] Sent '2........'
/usr/lib/python2.4/site-packages/pika-0.9.6_pre0-py2.4.egg/pika/canection.CloseOk"
[root@localhost python]# python new_task.py 3........
[x] Sent '3........'
/usr/lib/python2.4/site-packages/pika-0.9.6_pre0-py2.4.egg/pika/canection.CloseOk"
[root@localhost python]# python new_task.py 4........
[x] Sent '4........'
/usr/lib/python2.4/site-packages/pika-0.9.6_pre0-py2.4.egg/pika/canection.CloseOk"
[root@localhost python]# python new_task.py 5........
[x] Sent '5........'
信息接收器C1:
[root@localhost python]# python worker.py
[*] Waiting for messages. Toexit press CTRL+C
[x] Received '2........'
[x] Done
[x] Received '4........'
[x] Done
信息接收器C2:
[root@localhost python]# python worker.py
[*] Waiting for messages. Toexit press CTRL+C
[x] Received '1........'
[x] Done
[x] Received '3........'
[x] Done
[x] Received '5........'
[x] Done
当C1收到消息时候会告诉队列已经收到并处理完成,如果一条消息处理失败,队列会重发该消息直到消息成功处理才从队列中删除。
可以选择消息的持久化策略,计算RabbitMQ Server 重新启动了,队列里面的消息还在,关闭时消息是保持在硬盘上的。
2.消息确认(Message acknowledgment)
消息确认就是当接收器消息处理完成后,通知队列,消息已经处理完了,可以将消息删除了。如果队列在一定时间内未收到确认消息,将重发消息。
3.消息持久性(Message durability)
消息持久化的方法就是让队列里面的消息保持在硬盘上,这种方式应该建立队列的时候对其属性进行设置,具体如下:
channel.queue_declare(queue='task_queue',durable=True)
即设置durable=True
channel.basic_publish(exchange='',
routing_key="task_queue",
body=message,
properties=pika.BasicProperties(
delivery_mode =2, # make message persistent
))
即设置delivery_mode = 2。
测试结果如下:
1:发送了消息1111111;
2:停止了服务器;
3:启动服务器;
4:启动一个worker实例,接收到了信息。
4.公平调度(Fair dispatch)
当C1有一条消息还没有处理完成的时候,不会给他分发下一条消息,直到他把一条消息执行完了,再为它分配。
channel.basic_qos(prefetch_count=1)
三.发布/订阅(Publish/Subscribe)
该方式是传递相同的一条消息给多个Worker实例。
该模式测试用例:
发送消息截图:
2个接收器接收:
接收器1:
接收器2:
1.交换机(exchage)
RabbitMQ的一个核心的思想就是producer绝不会直接将消息发给队列,通常它根本不知道消息会传送给一个队列,取而代之的是消息会发送给exchage(x)。exchage是简单的。一方面它接收produc发来的消息,另一方面,它发送消息给队列。Exchage知道它接收到的消息是做什么的。消息是应该被发送给某个一个特别的队列,还是应该发送给许多的队列,或者直接将接收到的消息扔掉。这些规则是由exchage type决定的。有4种exchage type:direct,topic,headers,fanout。如下图:
fanout:所有bind到此exchange的queue都可以接收消息。
channel.exchange_declare(exchange='logs',type='fanout')
direct:通过routingKey和exchange决定的那个唯一的queue可以接收消息。
topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息。
2消息绑定(binding)
绑定器(Bind),将交换器和队列连接起来,并且封装消息的路由信息。
四.路由(Routing)
比如通过设置交换机类型为direct,我们将错误日志保存到一个硬盘文件,而仍然能够将所有的消息输出到控制台。
如上图,error绑定到第一个队列,其他3种绑定到第二种队列。
五.主题(Topics)
通过设置交换机的类型为topic,就可以实现该种策略,即实现路由的更灵活性。
六.远程调用(RPC)
上图中请求里面,reply_to设置回调队列,correlation_id设置请求的唯一id,将消息发送给rpc_queue,
Server处理了消息后根据reply_to的值,将返回值返回给该队列,客户端等待返回值,当值出现了,先检查correlation_id,如果正确就处理,不正常丢弃。
测试数据:
启动服务端:
客户端请求并得到响应: