以python语言为例演示rabbitmq的常用功能。
1、fanout扇出模式(向某个交换器发送消息,绑定了该交换器的queue都会收到相同的消息)
def fanout_way():
EXCHANGE = 'ali_callback_exchange'
# 生成socket
conn_params = pika.URLParameters('amqp://admin:admin@localhost:5672/%2F')
connection = pika.BlockingConnection(conn_params)
# 生成管道
channel = connection.channel()
ali_queue = channel.queue_declare(queue='ali_callback_queue', exclusive=False, auto_delete=False)
huawei_queue = channel.queue_declare(queue='huawei_callback_queue', exclusive=False, auto_delete=False)
# 声明交换器
declared_exchange = channel.exchange_declare(exchange=EXCHANGE, exchange_type='fanout')
# 绑定交换器
channel.queue_bind('ali_callback_queue', EXCHANGE)
channel.queue_bind('huawei_callback_queue', EXCHANGE)
for i in range(10, 20):
print(i)
channel.basic_publish(exchange=EXCHANGE,
routing_key='', # 不需要指定key,指定也无效,交换器会自动把消息发送到绑定的队列中
body=json.dumps({"name": i}).encode(encoding='utf-8'),
properties=pika.BasicProperties(message_id=uuid.uuid4().__str__())
)
connection.close()
2、direct直连模式(直接向某个queue发消息)
def direct_way():
EXCHANGE = 'ali_callback_exchange'
# 生成socket
conn_params = pika.URLParameters('amqp://admin:admin@localhost:5672/%2F')
connection = pika.BlockingConnection(conn_params)
# 生成管道
channel = connection.channel()
ali_queue = channel.queue_declare(queue='ali_callback_queue', exclusive=False, auto_delete=False)
# 声明交换器
declared_exchange = channel.exchange_declare(exchange=EXCHANGE, exchange_type='fanout')
for i in range(10, 20):
print(i)
channel.basic_publish(exchange='',
routing_key='ali_callback_queue',
body=json.dumps({"name": i}).encode(encoding='utf-8'),
properties=pika.BasicProperties(message_id=uuid.uuid4().__str__())
)
connection.close()
QUEUE = 'huawei_callback_queue'
EXCHANGE = 'huawei_callback_exchange'
def on_message_callback(channel, method, props, body):
content = json.loads(body.decode(encoding='utf-8'))
print(content)
# ack确认机制,告诉mq消息已被成功消费,可以删除该消息。否则消息会被标记为unacked状态,不会自动删除
channel.basic_ack(delivery_tag=method.delivery_tag)
# 生成socket
conn_params = pika.URLParameters('amqp://admin:admin@localhost:5672/%2F')
connection = pika.BlockingConnection(conn_params)
# 生成管道
channel = connection.channel()
# 每次只能从mq获取一条消息,直到channel.basic_ack确认之后,才能认领第二条
channel.basic_qos(prefetch_count=1)
channel.basic_consume(QUEUE, on_message_callback=on_message_callback, auto_ack=False)
channel.start_consuming()
将一个函数运行在远程计算机上并且等待从那儿获取结果时,就可以用MQ自带的RPC。换句话说就是生产者发布了一条消息,需要等待消费者返回结果的场景下。
客户端(生产者):
correlation_id = uuid.uuid4()
# 处理服务端返回的结果
def on_message_callback(self, c, method, props, body):
# 客户端等待回调队列里的数据。当有消息出现的时候,它会检查correlation_id属性。如果此属性的值与请求匹配,则继续处理。
if correlation_id != props.correlation_id:
return
data = json.loads(body.decode(encoding='utf-8'))
print(data)
c.basic_ack(delivery_tag=method.delivery_tag) # 回复确认消息
# 生成socket
conn_params = pika.URLParameters('amqp://admin:admin@localhost:5672/%2F')
connection = pika.BlockingConnection(conn_params)
# 生成管道
channel = connection.channel()
channel.basic_qos(prefetch_count=1)
# 声明一个callback_queue,服务端会将结果发送到这个queue
declared_callback_queue = channel.queue_declare(queue='callback_queue', exclusive=False, auto_delete=False)
# 发送消息给服务端
channel.basic_publish(exchange='',routing_key='task_queue',
properties=pika.BasicProperties(
# 告诉服务端将返回发到哪个队列
reply_to=declared_callback_queue.method.queue,
# correlation_id作用是将请求与响应一一匹配
correlation_id=correlation_id
),
body=json.dumps(body).encode(encoding='utf-8'))
# 监听callback_queue,处理服务端返回的结果
channel.basic_consume(queue=declared_callback_queue.method.queue, on_message_callback=on_message_callback)
channel.start_consuming()
# 结束监听
#channel.stop_consuming()
服务端(消费者):
def on_message_callback(channel, method, props, body):
content = json.loads(body.decode(encoding='utf-8'))
print(f'服务端收到了消息:{content}')
channel.basic_publish(exchange='',
routing_key=props.reply_to, # 这是关键
properties=pika.BasicProperties(correlation_id=props.correlation_id),
body=json.dumps({'msg': '消息处理成功'}).encode(encoding='utf-8'))
# 生成socket
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', credentials=pika.PlainCredentials('admin', 'admin')))
# 生成管道
channel = connection.channel()
# 声明一个queue
queue = channel.queue_declare(queue='task_queue', exclusive=False, auto_delete=True)
# 处理完这条再发下一条
channel.basic_qos(prefetch_count=1)
# 定义收到消息动作
channel.basic_consume(queue=queue.method.queue, on_message_callback=on_message_callback, auto_ack=True)
channel.start_consuming()