[如何实现延迟队列] RabbitMQ

119 阅读2分钟

八股

rabbitmq实现延迟队列的两种方式:

  1. 通过**死信队列 + TTL (Time To Live) **实现延迟任务

    image-20250113155600614

(图来源参考文章1)

  1. 官方提供插件形式

两者的缺点:

  1. 死信队列:使用死信队列实现延迟任务有个缺点,它不能实现随机延迟任务,每个无消费者的队列上只能设置一个 ttl(消息过期时间),所以只能实现固定过期时间的延迟任务。

  2. 延迟插件:使用延迟插件实现延迟任务有以下两个缺点:

    1. 消息丢失问题:消息在真的被投递到目标消息队列之前,是存放在接收到了这个消息的服务端本地的 Mnesia 里面。也就是说,如果这个时候还没有刷新磁盘,那么消息就会丢失;如果这个节点不可用了,那么消息也同样会丢失。
    2. 高并发问题:这种实现方式不支持高并发场景,因为它只有一个延迟交换机,当高并发或数据量比较大时执行效率就会比较低。

实现

下面是使用 死信+TTL 的实现生产者消费者例子:

producer.py

import pika


conn = pika.BlockingConnection(
pika.ConnectionParameters(
	host="localhost",
	port=5672,
	credentials=pika.PlainCredentials('admin', 'admin'),
)
)
channel = conn.channel()

# 只有当从 delayed_queue_ttl 过期并发送到 dlx_exchange 的消息的路由键恰好是 dlx_routing_key 时,这条消息才会被路由到 consumer.py 中的 real_queue_ttl 队列
channel.queue_declare(
  queue='delayed_queue_ttl',
	arguments={
		'x-message-ttl': 3000,
		'x-dead-letter-exchange': 'dlx_exchange',    
    'x-dead-letter-routing-key': 'dlx_routing_key'  # 指定死信消息的路由键
	}
)

# send msg
msg = "Test delayed msg"
channel.basic_publish(
	exchange='',
  routing_key='delayed_queue_ttl',
  body=msg
)
print(f"Msg sent to delayed queue: {msg}")
conn.close()

consumer.py

import pika


conn = pika.BlockingConnection(
  pika.ConnectionParameters(
    host='localhost',
    port=5672,
    credentials=pika.PlainCredentials('admin', 'admin')
  )
)
channel = conn.channel()

channel.exchange_declare(exchange='dlx_exchange', exchange_type='direct')
channel.queue_declare(queue='real_queue_ttl')
channel.queue_bind(exchange='dlx_exchange', queue='real_queue_ttl', routing_key='dlx_routing_key')  # 将 real_queue_ttl 队列绑定到了 dlx_exchange,使用的路由键是 dlx_routing_key。

def callback(ch, method, properties, body):
  print(f"Received msg: {body.decode()}")

print("Waiting...")
channel.basic_consume(queue='real_queue_ttl', on_message_callback=callback, auto_ack=True)
channel.start_consuming()

执行结果:

image-20250113182104327

想要本机测试需配置rabbitmq的环境,参考我之前的文章配置本地 RabbitMQ 运行环境

参考文章:

说说RabbitMQ延迟队列实现原理?

RabbitMQ延迟消息实现 by ChatGPT