(二)RabbitMQ python部分api的使用
写在前面的
以为日常做的东西杂,多,不经常写的话容易忘。记录一些api的说明,方便以后的使用。也供需要的剪子们参考(可能会有错误,有错请留言,尽情拍砖)
direct
a.直连,publisher发送消息后,投递到绑定到同一个exchange上的所有queue.消息路由是通过routing_key来路由,与queue_name没有太大的关系
要求:consumer的exchangename 和 routing_key 与 publisher要一致,否则消息不会被处理
b.消息会轮流给每个consumer发送
durable
使用durable=True声明queue是持久化的,这样即便MQ崩溃了重启后queue仍然存在,这样可以防止消息的丢失。
delivery_mode
除了要声明queue是持久化的外,还需声明message是持久化的basic_publish的properties参数指定message的属性 此处pika.BasicProperties中的delivery_mode=2指明message为持久的,这样一来RabbitMQ崩溃重启后queue仍然存在其中的message也仍。但需注意的是将message标记为持久的并不能完全保证message不丢失,因为从RabbitMQ接收到message到将其存储到disk仍需一段时间,若此时RabbitMQ崩溃则message会丢失。况且RabbitMQ不会对每条message做fsync动作。这时可通过publisher confirms实现更强壮的持久性保证。
a.exchange持久化,在声明时指定durable => 1
b.queue持久化,在声明时指定durable => 1
c.消息持久化,在投递时指定delivery_mode => 2(1是非持久化)
channel.basic_publish(exchange=’test_exchange’, routing_key=’standard_key’, body=’queue:group’, properties=pika.BasicProperties(content_type=’text/plain’, delivery_mode=1))
basic_ack
在处理完消息时,返回应答状态。你要默认加上,别忘了!!!
channel.basic_ack(delivery_tag = method.delivery_tag)
假如不返回应答状态,即使这个consumer处理完成当前的任务,他也不会去从任务池里取下个任务,会一直等待下去(这是不合理的),他处理完后不会去通知publish,是给mq说一声,我处理完了这个任务了,再给我一个任务吧。否则mq会认为,这家伙那么忙,我找别人干活去,不给他任务了。
no_ack
channel.basic_consume(on_message, ‘queuename’,no_ack=False);basic_consume里的参数里no_ack的含义为no_ack=False意思为,您需要手动设置一下,即调用basic_ack来决定消息处理是否处理完成.这种状态下,publish发送的任务会到任务池里,增加consume时,直接从任务池里取任务
当调用basic_consume(…no_ack=True…)时,所有的任务都会分配给当前正在执行的consume,因为mq会把当前的consume当成空闲状态,consume接受任务后,立即回给mq说干完了(和perfetch_count不冲突)。(例如:当前正在执行3个consume,当第四个consume来到后,会检索到任务池里没有任务,因为任务全部被consume执行了,所以publish再次执行4次才可以被第4个consume发现)
prefetch_count:
channel.basic_qos(prefetch_count= 1 ): 这个是流量控制,比如我有5个consumer在同时消费,publisher发送任务后,consumer自动去任务池里去获取任务,处理完后,再次去取任务,直到任务完全取完。每个consumer都最大分配1个任务。当第6个consumer来到后,也是直接拿起任务就干.
若prefetch_count=2,那么每个consumer最大容纳2个任务。比如任务池里有10个任务(假设任务是耗时的,很长时间才能处理完毕),当前只有3个consumer(a,b,c)在执行。任务分配的情况:a->1,b->2,c->3,a->4,b->5,c->6.(刚开始是抢任务,每个consumer抢一个,轮完后发现还有任务,再第二轮抢,此时a的第二轮有肯能是任务5,任务6,视其效率而定)任务7,8,9,10就得等待。此时第4个consumer到了,会拿到7,8。
举个通俗的例子:
学校买个10张桌子给1班,每个桌子最大可以做2个学生。 假如有10个学生,老师决定,每个桌子坐1个学生。刚好分完。假如有15个学生,那么部分桌子是2个人的,其余的还是1个人。此时,又来了一张桌子,又来了5个学生,老师说了,新桌子不准用,旧桌子啥时候坐满了,啥时候再用新桌子。那么第11张桌子只能等到第21个学生来了(桌子=consumer,学生=publisher,老师=规则)
passive
channel.exchange_declare(exchange="test_exchange", exchange_type="direct", passive=False, durable=True, auto_delete=False)
例如如果用户仅仅想查询某一个队列是否已存在,如果不存在,不想建立该队列,仍然可以调用queue.declare,只不过需要将参数passive设为true,传给queue.declare,如果该队列已存在,则会返回true;如果不存在,则会返回Error,但是不会创建新的队列.
Exclusive
排他队列,如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意三点:
其一,排他队列是基于连接可见的,同一连接的不同信道是可以同时访问同一个连接创建的排他队列的。
其二,“首次”,如果一个连接已经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同。
其三,即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除的。这种队列适用于只限于一个客户端发送读取消息的应用场景。
auto_delete
自动删除,如果该队列没有任何订阅的消费者的话,该队列会被自动删除。这种队列适用于临时队列