客户端 https://pika.readthedocs.org/en/latest/
RabbitMQ安装见另外一篇文章python rpc framework ---- callme/multiprocessing.managers
分享 http://download.csdn.net/detail/xiarendeniao/5781457
1.概念:
channel 我理解就是每个连接对应的一个操作标识(A Channel is the primary communication method for interacting with RabbitMQ. It is recommended that you do not directly invokethe creation of a channel object in your application code but ratherconstruct the a channel by calling the active connection’s channel()method.)exchange 交换区,一个用于分发数据的虚拟的概念(将queue与exchange绑定后,往exchange发送的消息会根据路由规则进入相应的已绑定的queue)
queue 数据队列
exchange和queue的关系:
In RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange.
A default exchange identified by an empty string: This exchange is special ? it allows us to specify exactly to which queue the message should go. The queue name needs to be specified in the routing_key parameter.
当exchange为空字符串时,basic_publish发出的消息会发往以routing_key为名字的queue里面去。(此时,routing_key不再是普通路由过滤条件,而是queue的名字)
2.六种使用模式 见图“rabbitmq-1.jpg”
如需要一个消息被多个消费者拿到,可用exchange绑定多个queue,消费者跟这些queue一一对应,那么生产者往这个exchange发送的消息会被路由到多个queue里面、接着被多个消费者都拿到(模式3)。
消费者获取消息时可指定是否需要ack(channel.basic_consume(callback,queue=queue_name,no_ack=True)):
是,当消费者ack以后消息才会从queue里面删除,如果在ack之前消费者挂掉了,该消息会被其他消费者拿到;
否,当消费者一拿到消息,消息就会从queue里面删除
当使用六种模式中的第二种时,可能会出现负载不均衡的情况:默认分发策略是一个消费者发一个任务,不管它有多少没处理完;当消费者拿到比较耗时的任务时就不合理了。
解决办法:channel.basic_qos(prefetch_count=1) This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don't dispatch a new message to a worker until it has processed and acknowledged the previous one.
擦,去年在互动百科做那个相关性分析项目时就有这个问题,一直以为无解呢!当时用的是activemq(见另一篇文章python--memcached---activemq),当一个消费者程序启动比较快,另几个启动晚一些的时候,queue里面的几个任务就都被先报到的消费者预订了。结果是先到的消费者累死累活,后到的消费者闲着没事干。
对于模式6,不明白correlation_id和reply_to有什么必要性,返回结果的queue和message的标识由业务逻辑控制打入message内部完全没问题嘛...这两个参数反正是由服务端(姑且这样称呼吧,其实也是一个从queue中取message做计算并往另一个queue塞结果message的程序)的业务逻辑解析的,又不是RabbitMQ内部针对这两个属性会做什么处理!相比而言,我觉得delivery_mode才有意义,RabbitMQ会把指定该属性为2的message持久化到硬盘上。
3.exchange的类型:
fanout 简单分发,message直接输出到已经绑定的queue
direct 定向分发,根据routing_key选择性输出到已绑定的(指定了相同routing_key的所有)queue
topic 多重选择输出,和direct类似,只是routing_key由.连接单词组成、并可用*和#作匹配
可由topic实现前两种类型
4.数据持久化:
queue持久化 channel.queue_declare(queue='task_queue', durable=True)
message持久化 channel.basic_publish(exchange='',
routing_key="task_queue",
body=message,
properties=pika.BasicProperties(
delivery_mode = 2, # make message persistent
))
如上操作还是可能会丢数据:服务器在rabbitmq收到数据和写盘结束的时间区间内挂掉时( http://www.rabbitmq.com/tutorials/tutorial-two-python.html)
官网说的解决办法是对于发数据的程序(生产者)需要做事务处理(channel使用transaction模式),或者使用确认机制(confirm mode)。且,两者不可同时使用(http://www.rabbitmq.com/confirms.html)
客户端
1.AMQP客户端如何获取Queue中消息的数量?
import pika
def on_callback(msg):
print msg
params = pika.ConnectionParameters(
host='localhost',
port=5672,
credentials=pika.credentials.PlainCredentials('guest', 'guest'),
)
# Open a connection to RabbitMQ on localhost using all default parameters
connection = pika.BlockingConnection(parameters=params)
# Open the channel
channel = connection.channel()
# Declare the queue
channel.queue_declare(
callback=on_callback,
queue="test",
durable=True,
exclusive=False,
auto_delete=False
)
# ...
# Re-declare the queue with passive flag
channel.queue_declare(
callback=on_callback,
queue="test",
durable=True,
exclusive=False,
auto_delete=False,
passive=True
)
<Method(['frame_type=1', 'channel_number=1', "method=<Queue.DeclareOk(['queue=test', 'message_count=0', 'consumer_count=0'])>"])>
<Method(['frame_type=1', 'channel_number=1', "method=<Queue.DeclareOk(['queue=test', 'message_count=0', 'consumer_count=0'])>"])>
http://stackoverflow.com/questions/8192584/get-queue-size-in-pika-amqp-python