rabbitmq
一.rabbitmq 安装
详情见:http://www.cnblogs.com/yangh965/p/5862347.html
windows:
1.安装Erlang
2.安装rabbitmq
3.安装插件
4.http://127.0.0.1:15672/ 测试
5.添加用户
linux:
二.安装第三方库pika
pip3 install pika
三.rabbitmy消息队列的结束
rabbitmq与queue的区别:rabbitmy支持两个程序之间的交互
官网有详细的教程:http://www.rabbitmq.com/
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务
四:简单的消息队列(一对一,开启多个消费者也是一个生产者向一个消费者逐一的发送数据)
注: 防止消费者挂掉,需要增加确认消息
ch.basic_ack(delivery_tag = method.delivery_tag)
no_ack=False
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika #建立一个连接实例 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) #默认端口,可不写 #创建一个管道 channel = connection.channel() #创建一个队列,如果存在则不创建 channel.queue_declare(queue='hello') #通过exchange 将消息发送到队列 channel.basic_publish( exchange="", #基本的队列,参数为空 routing_key='hello',#队列的名字 body='hello world!'#消息内容 ) print('[x] Sent "hello world"') #关闭连接 connection.close()
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import time #创建一个连接的实例 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个管道 channel = connection.channel() #创建一个名为hello的队列,如果服务器中存在,则不创建 channel.queue_declare(queue='hello') #回调函数 def callback(ch,method,properties,body): print('[x] Received %s'% body) #模拟服务器宕机的情形 ,在10秒内终止程序运行 time.sleep(10) #告诉生产者,消息出来完成 ch.basic_ack(delivery_tag=method.delivery_tag) #消费消息 channel.basic_consume( callback, #如果有消息,调用回调函数处理 queue='hello',#到哪个队列取消息 # no_ack=True # 不写的话使用:默认no_ack=False,如果机器宕机,重新启动,还可以接受到未处理的队列消息 一般不写 # no_ack=True 写的话,机器宕机,以前的队列消息丢失 ) print('[*] Waiting for messages,To exit press CTRL+C') #开始消费消息 channel.start_consuming()
注:防止rabbitmq服务器挂掉,那么需要持久化
channel.queue_declare(queue='hello2',durable=True)
properties=pika.BasicProperties(
delivery_mode=2,# 使消息持久化
)
注:按能力分配消息
channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika #创建一个连接的实例 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) #创建一个管道 channel = connection.channel() #创建队列,队列名不能与存在的相同,持久化durable=True channel.queue_declare(queue='hello2',durable=True) #向队列中放入消息 channel.basic_publish( exchange='', #简单模式 body='hello world',#消息内容 routing_key='hello2', #队列名 properties=pika.BasicProperties( delivery_mode=2,# 使消息持久化 ) ) print('[x] Sent "Hello World"') #关闭连接 connection.close()
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import time #创建一个连接实例 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个管道 channel = connection.channel() #声明一个队列,不存在则创建,持久化 channel.queue_declare(queue='hello2',durable=True) #回调函数 def callback(ch,method,properties,body): print('[x] Received %r'%body) time.sleep(10) ch.basic_ack(delivery_tag=method.delivery_tag) # 向生产者发送处理完成的消息 #类似权重,按能力分发消息 channel.basic_qos(prefetch_count=1) #消费消息 channel.basic_consume( callback, #设置回调函数 queue='hello2', #设置队列 #no_ack=True # 一般不写 ) print('[*] Waiting for message,To exit press CTRL+C') #开始消费 channel.start_consuming()
五.复杂的消息队列(exchange)(一对多,一个生产者向多个消费者同时发相同的数据)
exchange三种类型:
fanout: 所有绑定到此exchange的queue都可以接收消息
direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息
topic: 所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息
1.fanout:广播消息
需要queue和exchange绑定,因为消费者不是和exchange直连的,消费者是连在queue上,queue绑定在exchange上,消费者只会在queue里取消息
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) channel = connection.channel() #声明广播管道,不需要声明队列 channel.exchange_declare( exchange='logs',#交换机的名字 type='fanout' ) # message = ' '.join(sys.argv[1:]) message = 'info:hello world' channel.basic_publish( exchange='logs', #指定交换机 routing_key='',# 此处为空,必须有 body=message ) print('[x] Sent %s'% message) connection.close()
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() #声明广播管道 channel.exchange_declare( exchange='logs', type='fanout' ) #不指定队列名字,rabbit会随机分配一个名字,exclusive=True会在使用此队列的消费者在断开后,将队列自动删除 result = channel.queue_declare(exclusive=True) #获取随机的队列的名字 queue_name = result.method.queue print('random queue name:',queue_name) #将随机生成的队列绑定到管道上 channel.queue_bind( exchange='logs', #指定交换机的名字 queue=queue_name ) print('[*] Waiting for los ,To exit press CTRL+C') def callback(ch,method,properties,body): print('[x]%r'%body) #消费消息 channel.basic_consume( callback, queue=queue_name, no_ack=True # 广播消息实时的,丢失无关紧要 ) channel.start_consuming()
2.direct:关键字发送消息
指定向某个队列发送消息,消费者的routing_key 要包含生产者的routing_key ,才能发送成功
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) channel=connection.channel() #声明交换机有选择的接收消息 channel.exchange_declare( exchange='direct_logs', type='direct' ) #重要的程度级别 默认为info severity一个字符串 severity = sys.argv[1] if len(sys.argv)> 1 else 'info' message = ' '.join(sys.argv[2:]) or 'hello world' channel.basic_publish( exchange='direct_logs', routing_key = severity, #根据severity 匹配要发送的队列 body=message ) print(" [x] Sent %r:%r" % (severity, message)) connection.close()
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel=connection.channel() channel.exchange_declare( exchange='direct_logs', type='direct' ) result = channel.queue_declare(exclusive=True) queue_name = result.method.queue #获取运行脚本参数 ,severties 多个字符串,只要有一个与 发送端相同,就可以处理消息 severities = sys.argv[1:] if not severities: sys.stderr.write('Usage:%s [info] [warning] [error]\n '% sys.argv[0]) sys.exit(1) #循环列表去绑定 for severity in severities: channel.queue_bind( exchange='direct_logs', queue=queue_name, routing_key=severity ) print('[*] Waiting for logs ,To exit press CTRL + C') def callback(ch,method,properties,body): print('[x] %s:%s'%(method.routing_key,body)) channel.basic_consume( callback, queue=queue_name, no_ack=True ) channel.start_consuming()
3.topic:模糊匹配
# 表示可以匹配 0 个 或 多个 单词
* 表示只能匹配 一个 单词
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672)) 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()
#!/usr/bin/env python # --*-- encoding:utf-8 --*-- import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel=connection.channel() channel.exchange_declare( exchange='topic_logs', type='topic' ) result = channel.queue_declare(exclusive=True) queue_name = result.method.queue binding_keys = sys.argv[1:] if not binding_keys: sys.stderr.write('Usage:%s [info] [warning] [error]\n '% 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] %s:%s'%(method.routing_key,body)) channel.basic_consume( callback, queue=queue_name, no_ack=True ) channel.start_consuming()
python publ.py aaa.info sbsb
python subs.py *.info #可以匹配成功
python publ.py aaa.info sbsb
python subs.py # #可以匹配成功
六.rabbitmq rpc实现
参考:http://blog.csdn.net/fgf00/article/details/52872730

浙公网安备 33010602011771号