rabbitmq介绍
RabbitMQ is a message broker. The principal idea is pretty simple: it accepts and forwards messages. You can think about it as a post office: when you send mail to the post box you're pretty sure that Mr. Postman will eventually deliver the mail to your recipient. Using this metaphor RabbitMQ is a post box, a post office and a postman.(rabbitmq官网介绍)
Hello World
第一个例子是hello world,官网上rabbitmq的客户端装的是pika。 [root@pxe ~]# pip install pika hello world模型最简单:
生产者 [root@pxe test]# cat rabbit_send.py #!/usr/bin/env python import pika conn = pika.BlockingConnection(pika.ConnectionParameters('localhost')) # 创建一个连接 channel = conn.channel() # 创建一个channel channel.queue_declare(queue='hello') # 创建一个hello队列 channel.basic_publish(exchange='',routing_key='hello',body='hello world!') # 往hello队列发送信息,routing_key跟具体队列名 print "Sent 'hello world" conn.close() # 关闭连接 消费者 # 从队列中接收消息比较复杂,需要订阅一个callback函数到队列中去。 [root@pxe test]# cat rabbit_rev.py import pika conn = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = conn.channel() channel.queue_declare(queue='hello') print "waiting for message!" def callback(ch, method, properties, body): print "receive %r" % body channel.basic_consume(callback,queue='hello',no_ack=True) # 从hello队列中接收消息 channel.start_consuming() # 这步相当于启动一个进程一直从hello队列中获取消息 执行结果 [root@pxe test]# python rabbit_send.py # 发送消息 Sent 'hello world' [root@pxe test]# rabbitmqctl list_queues name messages_ready messages_unacknowledged # 查看队列情况 Listing queues ... hello 1 0 ...done. [root@pxe test]# python rabbit_rev.py # 接收消息 waiting for message! receive 'hello world!'
Work queues
第二个例子演示的是多个消费者轮询从队列中接收消息 模型如下:
生产者 [root@pxe test]# cat rabbit_task.py #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) # 创建一个连接 channel = connection.channel() # 创建一个channel channel.queue_declare(queue='task_queue', durable=True) # 宣告一个持久化队列,队列名为task_queue,durable为True的时候,rabbitmq重启队列也不会消失 message = ' '.join(sys.argv[1:]) or "Hello World!" channel.basic_publish(exchange='',routing_key='task_queue',body=message,properties=pika.BasicProperties(delivery_mode=2)) # delivery_mode=2使message存到disk上,但这并不是百分百保证消息不会丢 print "Sent %r" % message connection.close()
消费者 [root@pxe test]# cat rabbit_worker.py #!/usr/bin/env python import pika import time connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) # 创建一个连接 channel = connection.channel() # 创建一个channel channel.queue_declare(queue='task_queue', durable=True) # 宣告一个持久化队列 print ' [*] Waiting for messages. To exit press CTRL+C' def callback(ch, method, properties, body): # 回调函数 print "Received %r" % body time.sleep(body.count('.')) # 纯粹是为了演示效果 print "Done" ch.basic_ack(delivery_tag = method.delivery_tag) # no_ack不为True的情况下,消费者进程挂掉的时候,所有未确认的消息都会被重传 channel.basic_qos(prefetch_count=1) # 让不同的worker进程轮询接收消息 channel.basic_consume(callback,queue='task_queue') channel.start_consuming() 执行结果 [root@pxe test]# python rabbit_task.py first. Sent 'first.' [root@pxe test]# python rabbit_task.py second.. Sent 'second..' [root@pxe test]# python rabbit_task.py third... Sent 'third...' [root@pxe test]# python rabbit_task.py fourth.... Sent 'fourth....' [root@pxe test]# python rabbit_task.py fifth..... Sent 'fifth.....' shell-1 [root@pxe1 test]# python rabbit_worker.py [*] Waiting for messages. To exit press CTRL+C Received 'first.' Done Received 'third...' Done Received 'fifth.....' Done shell-2 [root@pxe2 test]# python rabbit_worker.py [*] Waiting for messages. To exit press CTRL+C Received 'second..' Done Received 'fourth....' Done
Topics
基于topic exchange没有唯一的routing_key,它可能是一些word的集合,通常这些word会表明它的feature.
* 代表一个word
# 代表0或多个word
1、routing_key "quick.orange.rabbit"的消息会被发送到Q1、Q2
2、routing_key "quick.orange.fox" 的消息只会被发送到Q1
3、routing_key "lazy.brown.fox" 的消息只会被发送到Q2
4、routing_key "lazy.orange.male.rabbit" 的消息只会匹配最后一个word,会被发到Q2
# 下面是官方的一个例子 [root@controller001 home]# cat emit_log_topic.py #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='topic_logs',type='topic') routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info' message = ' '.join(sys.argv[2:]) or 'Hello World!' channel.basic_publish(exchange='topic_logs',routing_key=routing_key,body=message) print "[x] Sent %r:%r" % (routing_key, message) connection.close() [root@controller001 home]# cat receive_logs_topic.py import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() result = channel.queue_declare(exclusive=True) queue_name = result.method.queue binding_keys = sys.argv[1:] if not binding_keys: print >> sys.stderr, "Usage: %s [binding_key]..." % (sys.argv[0],) sys.exit(1) for binding_key in binding_keys: channel.queue_bind(exchange='topic_logs',queue=queue_name,routing_key=binding_key) print "[*] waiting for logs. To exit press CTRL+C" def callback(ch, method, properties, body): print "[x] %r:%r" % (method.routing_key, body,) channel.basic_consume(callback,queue=queue_name,no_ack=True) channel.start_consuming() 运行结果 [root@controller001 home]# python receive_logs_topic.py "kern.*" [*] waiting for logs. To exit press CTRL+C [root@controller001 home]# python emit_log_topic.py "kern.critical" "A critical kernel error" [x] Sent 'kern.critical':'A critical kernel error'
参考链接
rabbitmq tutorials