RabbitMQ - 2 簡單模式

簡單模式 

The Python code based on pika==1.0.0 version

producer:
  channel.basic_publish(
    exchange = ``,
    routing_key = 'hello',
    body = “世界你好!”
  )
	- 這種交換是特殊的‒它使我們可以準確地指定消息應進入的隊列。隊列名稱需要在routing_key參數中指定.

consumer:
  channel.basic_consume(
    queue='hello', 
    on_message_callback=callback,
    auto_ack=True
  )

  

Putting it all together

send.py

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='hello')  # 隊列的聲明是冪等的

channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

receive.py

#!/usr/bin/env python
import pika, sys, os

def main():
    connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='hello')

    def callback(ch, method, properties, body):
        print(" [x] Received %r" % body)

    channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)

    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('Interrupted')
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)

  

 消息確認機制

 鋪墊:同生產者消費者模型,消費者在處理消息後要向隊列發送消息回執,表明該消息已被消息掉。

 官網解釋:bool auto_ack: if set to True, automatic acknowledgement mode will be used

 該參數默認爲False,意味着RabbitMQ會消耗越來越多的內存,因爲它無法釋放那些未被確認的消息。

 當設置爲True時: 如果一個消費者在處理消息過程中掛掉了,那麼這個消息就丟失了,並且還丟失了發送給此消費者所有尚未處理的消息。

 這種情況肯定不是我們想要的,當一個消費者掛掉,如果能重新把消息發給其他消費者,這樣,我們的消息就不會丟失任何消息了。要如何做呢? (消息持久化+工作隊列+任務派遣)

 

消息持久化

當RabbitMQ服務掛掉時,隊列和消息都會丟失,要想不丟失,需要做持久化。

# 隊列持久化
channel.queue_declare(queue='hello', durable=True)  

# 消息持久化
發送端:
  channel.basic_publish(
	  exchange='',
	  routing_key='task_queue',
	  body=message,
	  properties=pika.BasicProperties(
	  delivery_mode=2, # make message persistent
	  ))

消費端:
def callback(ch, method, properties, body):
	print(" [x] Received %r" % body.decode())
	ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(queue='task_queue', on_message_callback=callback, auto_ack=False)

工作隊列

工作隊列又叫任務隊列

使用場景:當一個消費者處理一條消息很耗時,我又不想等待它完成,想把消息分發給其他消費者時

準備:一個生產者、多個消費者

MQ將按順序地將每個消息發送給下一個消費者,平均而言,每個消費者都會收到相同數量的消息,這種分發方式稱爲循環。

以循環方式分發消息仍然不能解決上述場景的問題,理想情況是公平的分發消息(在消費者忙碌時就把消息發給不忙的消費者)

公平派遣/公平分發

爲了克服這個問題,我們可以將 Channel#basic_qos通道方法與 prefetch_count = 1設置一起使用。

使用basic.qos協議方法來告訴RabbitMQ一次不向消費者發送多條消息。換句話說,在處理並確認上一條消息之前,不要將新消息發送給消費者。而是將其分派給不忙的下一個消費者。

channel.basic_qos(prefetch_count = 1)

關於隊列大小的注意事項

如果所有工作人員都忙,您的隊列就滿了。您將需要注意這一點,並可能增加更多的工作人員,或使用消息TTL

Putting it all together

 send.py

#!/usr/bin/env python
import pika
import sys

connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='task_queue', durable=True)

message = ' '.join(sys.argv[1:]) or "Hello World!"
channel.basic_publish(
    exchange='',
    routing_key='task_queue',
    body=message,
    properties=pika.BasicProperties(
        delivery_mode=2,  # make message persistent
    ))
print(" [x] Sent %r" % message)
connection.close()

receive.py

#!/usr/bin/env python
import pika
import time

connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost'))
channel = connection.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(" [x] Received %r" % body.decode())
    time.sleep(body.count(b'.'))
    print(" [x] Done")
    ch.basic_ack(delivery_tag=method.delivery_tag)


channel.basic_qos(prefetch_count=1)
channel.basic_consume(queue='task_queue', on_message_callback=callback)

channel.start_consuming()

 

 

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章