python操作rabbitmq

 1、普通生产消费:

--------------------------------------------------------------------------------
productor:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/')) 
channel = connection.channel()

channel.queue_declare(queue='rhj')

channel.basic_publish(exchange='',
                      routing_key='rhj',
                      body='Hello World!')
connection.close()
--------------------------------------------------------------------------------
consumer: #!/usr/bin/env python # -*- coding: utf-8 -*- import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/')) channel = connection.channel() def callback(channel, method, properties, message): print("get resultc from queue %s" % message) channel.basic_consume(callback, # 消息处理回调函数 queue='rhj', no_ack=True) # 不需要回消息 channel.start_consuming()
----------------------------------------------------------------------------------
结果:
执行完productor后:

  执行consumer:

  

  消费完成,获取到消息,并未回,队列消息已不存在:

  

需要回消息的情况,需要改造消费者:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()


def callback(channel, method, properties, message):
    print("get result from queue %s" % message)
    # channel.basic_ack(delivery_tag=method.delivery_tag) # 回消息


channel.basic_consume(callback,
                      queue='rhj') # 不定义no_ack,默认为False


channel.start_consuming()
----------------------------------------------------------------------------------
结果:
执行完productor后:
执行consumer:

  

消费完成,获取到消息,并未回,队列消息仍然存在:

  取消注释,在消费时候回消息,队列消息被删除:

def callback(channel, method, properties, message):
    print("get result from queue %s" % message)
    channel.basic_ack(delivery_tag=method.delivery_tag) # 回消息

2、持久化

前面的队列和消息都是没有持久化的,当rabbitmq-server重启,队列就会丢失,所以下面讨论持久化:

可以看到,我们前面申明的队列已经不存在了,因为源码默认是不持久化的:

下面我们修改代码,为队列申明持久化,然后执行:

#生产者
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()
channel.queue_declare(queue='rhj', durable=True) # 申明队列持久化

channel.basic_publish(exchange='',
                      routing_key='rhj',
                      body='Hello World!')
connection.close()
-----------------------------------------------------------------------------------
执行后,发现队列持久化了,但是消息不见了,那怎么完成消息也持久化:

 

  为了完成消息持久化,我们继续修改代码:

channel.basic_publish(exchange='',
                      routing_key='rhj',
                      body='Hello World!',
                      properties=pika.BasicProperties(delivery_mode=2)) #delivery_mode为2为持久化,为1不持久化
执行后,发现队列和消息都完成了持久化:

   如果我们不为队列持久化,但是为消息持久化会发生什么?:

结局是不允许,要申请内容持久化,一定要队列持久化为True,否则会抛异常。

3、队列的durable,exclusive,auto_delete。

durable上面已经知道什么意思了,下面看看令两种,

先在生产者什么队列时加一个参数,

增加一个队列申明如下:

channel.queue_declare(queue='rhj_temp',exclusive=True)

 结果什么都没发生,其实看注释,是因为当前连接已关闭,该队列已删除了:

把这条命令加到consumer里就能看到变化了,在consumer连接存在时,队列存在,关闭时,队列删除:

可以看出,durable是持久化,exclusive是连接结束时关闭,如果同时存在会怎么样,我们在消费者为队列同时添加两个属性?

channel.queue_declare(queue='rhj_temp', durable=True, exclusive=True)

按设置,这个队列是应该持久化的,而且在终止连接会删除,有矛盾,结果是怎样的呢?

队列不见了,说明同时设置durable和exclusive为True,生效的是exclusive;

下面再看auto_delete,看源码描述:

和exclusive有啥区别呢,先看下exclusive开两个队列会怎样:

报错了,因为exclusive是排他的,不允许其他消费者共享,绑定的是单个连接,然后再看auto_delete,

我们对代码做些改动,申明一个队列,auto_delete=True:

channel.queue_declare(queue='rhj_tmp', auto_delete=True)

执行两次,不会保错,两个消费者都存在,说明auto_delete是允许共享的,

 

继续看队列,看下图,只有在最后一个消费者被干掉的时,队列才会会删除,否则队列一直存在,:

现在这三个参数的含义应该清楚了。

 4、exchange

rabbitmq有四种exchange,分别是Direct exchange,Fanout exchange,Topic exchange和Headers exchange。

执行命令查看下rabbitmq的默认exchange,所以说我们上面指定exchange=''是指定了最后一个默认的direct的exchange,我们看到,每个类型都有默认的exchange。

第一个看fanout:

fanout是广播式交换机,即将同一个message发送到所有同该Exchange 绑定的queue。不论RoutingKey是什么,这条消息都会被投递到所有与此Exchange绑定的queue中,修改生产者代码,申明一个exchange,指定消息发到该exchange:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))

channel.exchange_declare(exchange='rhj_fanout',
                         exchange_type='fanout')

channel.basic_publish(exchange='rhj_fanout',
routing_key='', #不需要routing_key,配了也没用, 但是参数必须有,这设计。。。 body
='Hello World!') connection.close()

执行该生产者,生成了我们定义的exchange,类型为fanout:

修改消费者代码:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()

channel.queue_declare(queue='rhj_tmp', auto_delete=True) # 申明自动删除的队列
channel.queue_bind(exchange='rhj_fanout', queue='rhj_tmp') # 绑定队列到exchange

def callback(channel, method, properties, message):
    print("get result from queue %s" % message)
    channel.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(callback,
                      queue='rhj_tmp')

channel.start_consuming()

执行consumer后,自动创建了rhj_tmp这个队列,且绑定到了rhj_fanout上,我们查看下绑定信息,看到除了默认exchange,和我们代码一致:

然后执行productor,往该exchange发一条信息,consumer表现如下:

consumer成功消费到了消息,可以看到,我们在不需要RoutingKey时通过广播exchange把消息发送到队列并成功消费到。

第二个看direct:

Direct是直接交换机,根据Binding指定的Routing Key,将符合Key的消息发送到Binding的Queue。可以构建点对点消息传输模型,

这个就需要RoutingKey了,而且RoutingKey必须和队列一致,否则就无法路由到该队列,生产者代码:

import pika


connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()
channel.exchange_declare(exchange='rhj_director',
                         exchange_type='direct')


channel.basic_publish(exchange='rhj_director',
                      routing_key='rhj.tmp',
                      body='Hello World!')
connection.close()

执行生产者代码,生成exchange:

而且exchange因为没有对应的队列,消息被丢弃,消息不回发到默认exchange对应的队列,

消费者代码:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()

channel.queue_declare(queue='rhj.*', auto_delete=True)
channel.queue_bind(exchange='rhj_director', queue='rhj.*') # 绑定exchange

def callback(channel, method, properties, message):
    print("get result from queue %s" % message)
    channel.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(callback,
                      queue='rhj.*')

channel.start_consuming()

执行消费者代码,什么都消费不到,因为队列rhj.*为空,消息由于routing_key的原因,无法发到队列里,

修改生成者代码,再执行:

channel.basic_publish(exchange='rhj_director',
                      routing_key='rhj.*',
                      body='Hello World!')

第三说下Topic,

Topic Exchangetopic是最常用的一种exchange,叫主题交换机,根据Binding指定的RoutingKey,Exchange对key进行模式匹配后投递到相应的Queue,模式匹配时符号“#”匹配一个或多个词,符号“*”匹配正好一个词,而且单词与单词之间必须要用“.”符号进行分隔。

生产者代码:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()

channel.exchange_declare(exchange='rhj_topic',
                         exchange_type='topic')

channel.basic_publish(exchange='rhj_topic',
                      routing_key='rhj.tmp',
                      body='Hello World!')
connection.close()

消费者代码,绑定rhj_topic:

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672, '/'))
channel = connection.channel()

channel.queue_declare(queue='*.tmp', auto_delete=True)
channel.queue_declare(queue='rhj.*', auto_delete=True)
channel.queue_bind(exchange='rhj_topic', queue='*.tmp')
channel.queue_bind(exchange='rhj_topic', queue='rhj.*') 
def callback(channel, method, properties, message): print("get result from queue %s" % message) channel.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(callback, queue='rhj.*') channel.start_consuming()

执行生产者代码,发现*.tmp和rhj.*两个队列都收到了消息:

执行消费者,消费到了消息,消费了的队列消息删除,未消费的则保留:

具体其他模式匹配,请自己进程尝试。

最后还有一种header交换器,这种通常使用的比较少,是使用headers进行匹配路由到指定Queue,这里不多介绍了。

另外exchange声明的时候也是可以指定durable和auto_delete的,含义上面介绍过了,要注意,持久化的exchange只能与持久化的queue进行bind,否则会报错。

posted @ 2018-08-04 16:04  Small_office  阅读(991)  评论(0编辑  收藏  举报