python-如何在RabbitMQ中创建延迟的队列?
使用Python,Pika和RabbitMQ创建延迟(或停放)队列的最简单方法是什么? 我见过类似的问题,但Python没有。
在设计应用程序时,我发现这是一个有用的想法,因为它使我们能够限制需要再次重新排队的消息。
总是有可能收到的消息超出您的处理能力,例如HTTP服务器速度慢或数据库承受的压力太大。
我还发现,在丢失消息的容忍度为零的情况下出现问题时,如果出现问题,并且对无法处理的消息进行重新排队可能会解决此问题,那么它非常有用。 它还可能会导致问题,使消息一遍又一遍地排队。 潜在导致性能问题,并记录垃圾邮件。
6个解决方案
88 votes
我发现在开发应用程序时这非常有用。 因为它为您提供了简单地重新排队消息的替代方法。 这可以轻松降低代码的复杂性,并且是RabbitMQ中许多强大的隐藏功能之一。
脚步
首先,我们需要设置两个基本通道,一个用于主队列,一个用于延迟队列。 在最后的示例中,我添加了一些不需要的其他标志,但是使代码更可靠。 例如confirm delivery、delivery_mode和durable。您可以在RabbitMQ手册中找到有关这些信息的更多信息。
设置通道后,我们将绑定添加到主通道,可用于将消息从延迟通道发送到主队列。
channel.queue_bind(exchange='amq.direct',
queue='hello')
接下来,我们需要配置延迟通道,以在消息过期后将其转发到主队列。
delay_channel.queue_declare(queue='hello_delay', durable=True, arguments={
'x-message-ttl' : 5000,
'x-dead-letter-exchange' : 'amq.direct',
'x-dead-letter-routing-key' : 'hello'
})
x-message-ttl(消息-生存时间)
通常用于自动删除邮件中的旧邮件在特定持续时间后排队,但是通过添加两个可选参数,我们可以更改此行为,而是让此参数确定以毫秒为单位的消息将在延迟队列中保留多长时间。
x死信路由键
这个变量允许我们将消息转移到另一个队列它们过期后,而不是默认的删除行为它完全。
x死信交换
此变量确定哪个Exchange用于将邮件从hello_delay传输到hello队列。
发布到延迟队列
完成所有基本的Pika参数设置后,您只需使用基本发布就可以将消息发送到延迟队列。
delay_channel.basic_publish(exchange='',
routing_key='hello_delay',
body="test",
properties=pika.BasicProperties(delivery_mode=2))
一旦执行了脚本,您将看到在RabbitMQ管理模块中创建的以下队列。
例。
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
'localhost'))
# Create normal 'Hello World' type channel.
channel = connection.channel()
channel.confirm_delivery()
channel.queue_declare(queue='hello', durable=True)
# We need to bind this channel to an exchange, that will be used to transfer
# messages from our delay queue.
channel.queue_bind(exchange='amq.direct',
queue='hello')
# Create our delay channel.
delay_channel = connection.channel()
delay_channel.confirm_delivery()
# This is where we declare the delay, and routing for our delay channel.
delay_channel.queue_declare(queue='hello_delay', durable=True, arguments={
'x-message-ttl' : 5000, # Delay until the message is transferred in milliseconds.
'x-dead-letter-exchange' : 'amq.direct', # Exchange used to transfer the message from A to B.
'x-dead-letter-routing-key' : 'hello' # Name of the queue we want the message transferred to.
})
delay_channel.basic_publish(exchange='',
routing_key='hello_delay',
body="test",
properties=pika.BasicProperties(delivery_mode=2))
print " [x] Sent"
eandersson answered 2020-07-23T16:25:20Z
16 votes
您可以使用RabbitMQ官方插件:x-delayed-message。
首先,下载ez文件并将其复制到Your_rabbitmq_root_path / plugins
其次,启用插件(无需重新启动服务器):
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
最后,发布带有“ x-delay”标头的消息,例如:
headers.put("x-delay", 5000);
注意:
它不能确保您的消息的安全,因为如果您的消息仅在Rabbitmq服务器停机期间到期,则消息会丢失。 因此,使用此方案时请务必小心。
享受它和rabbitmq-delayed-message-exchange中的更多信息
flycee answered 2020-07-23T16:26:08Z
8 votes
仅供参考,如何在Spring 3.2.x中执行此操作。
10000
Ryan Walls answered 2020-07-23T16:26:27Z
4 votes
NodeJS实现。
代码中的所有内容都很清楚。希望它可以节省别人的时间。
var ch = channel;
ch.assertExchange("my_intermediate_exchange", 'fanout', {durable: false});
ch.assertExchange("my_final_delayed_exchange", 'fanout', {durable: false});
// setup intermediate queue which will never be listened.
// all messages are TTLed so when they are "dead", they come to another exchange
ch.assertQueue("my_intermediate_queue", {
deadLetterExchange: "my_final_delayed_exchange",
messageTtl: 5000, // 5sec
}, function (err, q) {
ch.bindQueue(q.queue, "my_intermediate_exchange", '');
});
ch.assertQueue("my_final_delayed_queue", {}, function (err, q) {
ch.bindQueue(q.queue, "my_final_delayed_exchange", '');
ch.consume(q.queue, function (msg) {
console.log("delayed - [x] %s", msg.content.toString());
}, {noAck: true});
});
walv answered 2020-07-23T16:26:52Z
0 votes
Rabbit队列中的消息可以通过两种方式延迟 -使用队列TTL -使用消息TTL如果要将队列中的所有消息延迟固定时间,请使用队列TTL。如果每条消息都必须通过不同的时间延迟,请使用消息TTL。我已经使用python3和pika模块解释了它。必须将pika BasicProperties参数“ expiration”(以毫秒为单位)设置为延迟延迟队列中的消息。设置到期时间后,将消息发布到delay_queue(“消费者等待消费的非实际队列”),一旦delay_queue中的消息到期,将使用交换“ amq.direct”将消息路由到实际队列
def delay_publish(self, messages, queue, headers=None, expiration=0):
"""
Connect to RabbitMQ and publish messages to the queue
Args:
queue (string): queue name
messages (list or single item): messages to publish to rabbit queue
expiration(int): TTL in milliseconds for message
"""
delay_queue = "".join([queue, "_delay"])
logging.info('Publishing To Queue: {queue}'.format(queue=delay_queue))
logging.info('Connecting to RabbitMQ: {host}'.format(
host=self.rabbit_host))
credentials = pika.PlainCredentials(
RABBIT_MQ_USER, RABBIT_MQ_PASS)
parameters = pika.ConnectionParameters(
rabbit_host, RABBIT_MQ_PORT,
RABBIT_MQ_VHOST, credentials, heartbeat_interval=0)
connection = pika.BlockingConnection(parameters)
channel = connection.channel()
channel.queue_declare(queue=queue, durable=True)
channel.queue_bind(exchange='amq.direct',
queue=queue)
delay_channel = connection.channel()
delay_channel.queue_declare(queue=delay_queue, durable=True,
arguments={
'x-dead-letter-exchange': 'amq.direct',
'x-dead-letter-routing-key': queue
})
properties = pika.BasicProperties(
delivery_mode=2, headers=headers, expiration=str(expiration))
if type(messages) not in (list, tuple):
messages = [messages]
try:
for message in messages:
try:
json_data = json.dumps(message)
except Exception as err:
logging.error(
'Error Jsonify Payload: {err}, {payload}'.format(
err=err, payload=repr(message)), exc_info=True
)
if (type(message) is dict) and ('data' in message):
message['data'] = {}
message['error'] = 'Payload Invalid For JSON'
json_data = json.dumps(message)
else:
raise
try:
delay_channel.basic_publish(
exchange='', routing_key=delay_queue,
body=json_data, properties=properties)
except Exception as err:
logging.error(
'Error Publishing Data: {err}, {payload}'.format(
err=err, payload=json_data), exc_info=True
)
raise
except Exception:
raise
finally:
logging.info(
'Done Publishing. Closing Connection to {queue}'.format(
queue=delay_queue
)
)
connection.close()
Kushwanth Mandadapu answered 2020-07-23T16:27:13Z
0 votes
根据您的情况和需求,我建议采用以下方法,
使用官方插件[https://www.rabbitmq.com/blog/2015/04/16/scheduling-messages-with-rabbitmq/],但如果延迟消息的总数超过一定值,它将出现容量问题 编号([https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/issues/72),]它不会具有高可用性选项,并且如果在此期间的延迟时间用尽,它将丢失数据 MQ重新启动。
像NServiceBus一样,实现一组级联的延迟队列([https://docs.particular.net/transports/rabbitmq/delayed-delivery)。]
henrylilei answered 2020-07-23T16:27:43Z