RabbitMQ可以当做一个消息代理,它的核心原理非常简单:即接收和发送消息,可以把它想象成一个邮局:我们把信件放入邮箱,邮递员就会把信件投递到你的收件人处,RabbitMQ就是一个邮箱、邮局、投递员功能综合体,整个过程就是:邮箱接收信件,邮局转发信件,投递员投递信件到达收件人处。
RabbitMQ和邮局的主要区别就是RabbitMQ接收、存储和发送的是二进制数据----消息。
rabbitmq基本管理命令:
一步启动Erlang node和Rabbit应用:sudo rabbitmq-server
在后台启动Rabbit node:sudo rabbitmq-server -detached
关闭整个节点(包括应用):sudo rabbitmqctl stop
add_user <UserName> <Password> delete_user <UserName> change_password <UserName> <NewPassword> list_users add_vhost <VHostPath> delete_vhost <VHostPath> list_vhosts set_permissions [-p <VHostPath>] <UserName> <Regexp> <Regexp> <Regexp> clear_permissions [-p <VHostPath>] <UserName> list_permissions [-p <VHostPath>] list_user_permissions <UserName> list_queues [-p <VHostPath>] [<QueueInfoItem> ...] list_exchanges [-p <VHostPath>] [<ExchangeInfoItem> ...] list_bindings [-p <VHostPath>] list_connections [<ConnectionInfoItem> ...]</div>
Demo:
producer.py
#!/usr/bin/env python
# -*- coding: utf_ -*-
# Date: 年月日
# Author:蔚蓝行
# 博客 http://www.cnblogs.com/duanv/
import pika
import sys
#创建连接connection到localhost
con = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
#创建虚拟连接channel
cha = con.channel()
#创建队列anheng,durable参数为真时,队列将持久化;exclusive为真时,建立临时队列
result=cha.queue_declare(queue='anheng',durable=True,exclusive=False)
#创建名为yanfa,类型为fanout的exchange,其他类型还有direct和topic,如果指定durable为真,exchange将持久化
cha.exchange_declare(durable=False,
exchange='yanfa',
type='direct',)
#绑定exchange和queue,result.method.queue获取的是队列名称
cha.queue_bind(exchange='yanfa',
queue=result.method.queue,
routing_key='',)
#公平分发,使每个consumer在同一时间最多处理一个message,收到ack前,不会分配新的message
cha.basic_qos(prefetch_count=)
#发送信息到队列‘anheng'
message = ' '.join(sys.argv[:])
#消息持久化指定delivery_mode=;
cha.basic_publish(exchange='',
routing_key='anheng',
body=message,
properties=pika.BasicProperties(
delivery_mode = ,
))
print '[x] Sent %r' % (message,)
#关闭连接
con.close()
</div>
consumer.py
#!/usr/bin/env python
# -*- coding: utf_ -*-
# Date: 年月日
# Author:蔚蓝行
# 博客 http://www.cnblogs.com/duanv/
import pika
#建立连接connection到localhost
con = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
#创建虚拟连接channel
cha = con.channel()
#创建队列anheng
result=cha.queue_declare(queue='anheng',durable=True)
#创建名为yanfa,类型为fanout的交换机,其他类型还有direct和topic
cha.exchange_declare(durable=False,
exchange='yanfa',
type='direct',)
#绑定exchange和queue,result.method.queue获取的是队列名称
cha.queue_bind(exchange='yanfa',
queue=result.method.queue,
routing_key='',)
#公平分发,使每个consumer在同一时间最多处理一个message,收到ack前,不会分配新的message
cha.basic_qos(prefetch_count=)
print ' [*] Waiting for messages. To exit press CTRL+C'
#定义回调函数
def callback(ch, method, properties, body):
print " [x] Received %r" % (body,)
ch.basic_ack(delivery_tag = method.delivery_tag)
cha.basic_consume(callback,
queue='anheng',
no_ack=False,)
cha.start_consuming()
</div>
一、概念:
Connection: 一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。程序的起始处就是建立这个TCP连接。
Channels: 虚拟连接。建立在上述的TCP连接中。数据流动都是在Channel中进行的。一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。
二、队列:
首先建立一个Connection,然后建立Channels,在channel上建立队列
建立时指定durable参数为真,队列将持久化;指定exclusive为真,队列为临时队列,关闭consumer后该队列将不再存在,一般情况下建立临时队列并不指定队列名称,rabbitmq将随机起名,通过result.method.queue来获取队列名:
result = channel.queue_declare(exclusive=True)
result.method.queue
区别:durable是队列持久化与否,如果为真,队列将在rabbitmq服务重启后仍存在,如果为假,rabbitmq服务重启前不会消失,与consumer关闭与否无关;
而exclusive是建立临时队列,当consumer关闭后,该队列就会被删除
三、exchange和bind
Exchange中durable参数指定exchange是否持久化,exchange参数指定exchange名称,type指定exchange类型。Exchange类型有direct,fanout和topic。
Bind是将exchange与queue进行关联,exchange参数和queue参数分别指定要进行bind的exchange和queue,routing_key为可选参数。
Exchange的三种模式:
Direct:
任何发送到Direct Exchange的消息都会被转发到routing_key中指定的Queue
1.一般情况可以使用rabbitMQ自带的Exchange:””(该Exchange的名字为空字符串);
2.这种模式下不需要将Exchange进行任何绑定(bind)操作;
3.消息传递时需要一个“routing_key”,可以简单的理解为要发送到的队列名字;
4.如果vhost中不存在routing_key中指定的队列名,则该消息会被抛弃。
Demo中虽然声明了一个exchange='yanfa'和queue='anheng'的bind,但是在后面发送消息时并没有使用该exchange和bind,而是采用了direct的模式,没有指定exchange,而是指定了routing_key的名称为队列名,消息将发送到指定队列。
如果一个exchange 声明为direct,并且bind中指定了routing_key,那么发送消息时需要同时指明该exchange和routing_key.
Fanout:
任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有Queue上
1.可以理解为路由表的模式
2.这种模式不需要routing_key
3.这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个Queue,一个Queue可以同多个Exchange进行绑定。
4.如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃。
Demo中创建了一个将一个exchange和一个queue进行fanout类型的bind.但是发送信息时没有用到它,如果要用到它,只要在发送消息时指定该exchange的名称即可,该exchange就会将消息发送到所有和它bind的队列中。在fanout模式下,指定的routing_key是无效的 。
Topic:
任何发送到Topic Exchange的消息都会被转发到所有关心routing_key中指定话题的Queue上
1.这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一个“标题”(routing_key),Exchange会将消息转发到所有关注主题能与routing_key模糊匹配的队列。
2.这种模式需要routing_key,也许要提前绑定Exchange与Queue。
3.在进行绑定时,要提供一个该队列关心的主题,如“#.log.#”表示该队列关心所有涉及log的消息(一个routing_key为”MQ.log.error”的消息会被转发到该队列)。
4.“#”表示0个或若干个关键字,“*”表示一个关键字。如“log.*”能与“log.warn”匹配,无法与“log.warn.timeout”匹配;但是“log.#”能与上述两者匹配。
5.同样,如果Exchange没有发现能够与routing_key匹配的Queue,则会抛弃此消息。
四、任务分发
1.Rabbitmq的任务是循环分发的,如果开启两个consumer,producer发送的信息是轮流发送到两个consume的。
2.在producer端使用cha.basic_publish()来发送消息,其中body参数就是要发送的消息,properties=pika.BasicProperties(delivery_mode = 2,)启用消息持久化,可以防止RabbitMQ Server 重启或者crash引起的数据丢失。
3.在接收端使用cha.basic_consume()无限循环监听,如果设置no-ack参数为真,每次Consumer接到数据后,而不管是否处理完成,RabbitMQ Server会立即把这个M

