文档章节

【原创】RabbitMQ 之 Dead Letter Exchanges(翻译)

摩云飞
 摩云飞
发布于 2015/03/04 10:19
字数 2410
阅读 600
收藏 2

Dead Letter Exchanges

Messages from a queue can be 'dead-lettered'; that is, republished to another exchange when any of the following events occur:
queue 中的消息可能成为“死信”;也就是说,会在下面任何一种情况发生时,重新 publish 消息到另外的 exchange 中:
  • The message is rejected (basic.reject or basic.nack) with requeue=false,
    消息被拒绝了(通过 basic.reject 方法或 basic.nack 方法),同时设置了 requeue=false 参数,
  • The TTL for the message expires; or
    消息本身设置了 TTL ,且达到了过期时间;或者
  • The queue length limit is exceeded.queue
    可持有消息数量达到了上限
Dead letter exchanges (DLXs) are normal exchanges. They can be any of the usual types and are declared as usual.
死信 exchang(DLXs)就是普通的 exchange 。其如普通 exchange 一样具有各种类型,也具有一样的声明方式。

For any given queue, a DLX can be defined by clients using the queue's arguments, or in the server using policies. In the case where both policy and arguments specify a DLX, the one specified in arguments overrules the one specified in policy.
对于任何给定的 queue ,客户端可以通过 queue 的 argument 参数指定 DLX ,或者直接在服务器侧 通过 policy 创建。如果出现同时使用两种方式创建了 DLX 的情况,则通过 argument 指定的 DLX 优先采用

Configuration using arguments
通过 argument 方式进行配置

To set the dead letter exchange for a queue, set the x-dead-letter-exchange argument to the name of the exchange:
如果要为某个 queue 设置 DLX ,则需要将 argument x-dead-letter-exchange 设置为 exchange 的名字:
channel.exchangeDeclare("some.exchange.name", "direct");

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "some.exchange.name");
channel.queueDeclare("myqueue", false, false, false, args);
The code above declares a new exchange called some.exchange.name and sets this new exchange as the dead letter exchange for a newly created queue. Note that the exchange does not have to be declared when the queue is declared, but it should exist by the time messages need to be dead-lettered; if it is missing then, the messages will be silently dropped.
上述代码声明了一个新的名为 some.exchange.name 的 exchange ,并且将该 exchange 设置成一个新创建 queue 的 DLX 。值得注意的是,当 queue 被声明的时候,该 exchange 并不要求已经被声明完成,但是当消息需要被当做“死信”处理的时候,该 exchange 必须已经存在。如果仍旧未存在,此时消息将被悄悄的丢掉(blackholed)。

You may also specify a routing key to be used when dead-lettering messages. If this is not set, the message's own routing keys will be used.
你同样可以指定一个 routing key 用于 DLX 分发消息。如果没有指定,那么消息本身使用的 routing key 将被使用。
args.put("x-dead-letter-routing-key", "some-routing-key");
When a dead letter exchange has been specified, in addition to the usual configure permissions on the declared queue, the user needs to have read permissions on that queue and write permissions on the dead letter exchange. Permissions are verified at the time of queue declaration.
当 DLX 被指定好后,对于被声明的 queue 而言,除了通常所需的 configure 权限,用户还需要具有对于该 queue 的 read 权限,和对于 DLX 的 write 权限。相应权限会在 queue 声明的时候被验证。

Configuration using policy
通过 policy 进行配置

To specify a DLX using policy, add the key "dead-letter-exchange" to a policy definition. For example:
通过 policy 来指定 DLX ,则需要在 policy 定义中添加 dead-letter-exchange 这个 key 值。例如:
rabbitmqctl
rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"my-dlx"}' --apply-to queues
rabbitmqctl (Windows)
rabbitmqctl set_policy DLX ".*" "{""dead-letter-exchange"":""my-dlx""}" --apply-to queues

This applies the DLX "my-dlx" to all queues.
上述配置将 DLX "my-dlx" 设置给所有 queue 。

Similarly, an explicit routing key can be specified by adding the key "dead-letter-routing-key" to the policy.
同样地,可以通过添加 key 值 dead-letter-routing-key 到 policy 中以显式指定 routing key 。

Policies can also be defined using the management plugin, see the policy documentation for more details.
policy 还可以通过管理插件进行定义,详情请 参考 policy 文档

Routing Dead-Lettered Messages
死信消息的路由

Dead-lettered messages are routed to their dead letter exchange either:
死信消息将会按照下面的方式被路由到其对应的 DLX 中:
  • with the routing key specified for the queue they were on; or, if this was not set,
    如果设置 DLX 时指定了 routing key ,则使用该 key 进行路由;
  • with the same routing keys they were originally published with.
    如果设置 DLX 时没有指定 routing key ,则使用消息被 publish 时采用的 key 。
For example, if you publish a message to an exchange with routing key foo, and that message is dead-lettered, it will be published to its dead letter exchange with routing key foo. If the queue the message originally landed on had been declared with x-dead-letter-routing-key set to bar, then the message will be published to its dead letter exchange with routing key bar.
例如,如果你使用 foo 作为 routing key 去 publish 了一条消息,并且发生了“死信”,那么该消息将被 publish 到其对应的 DLX 中将 foo 作为 routing key 进行路由。如果消息的目标 queue 在声明的时候设置了 x-dead-letter-routing-key 为 bar 到 argument 中,那么消息最终会使用 bar 作为 routing key 将消息发送到 DLX 中。

Note that, if a specific routing key was not set for the queue, messages on it are dead-lettered with all their original routing keys. This includes routing keys added by the CC and BCC headers (see Sender-selected distribution for details on these two headers).
值得注意的是,如果没有为 queue 设置特定的 routing key ,那么发送到该 queue 的消息在发生“死信”情况时,将分别使用其相应的 routing key 。这些 routing key 包括由 CC 和 BCC 头添加的那些( 详情参考 Sender-selected distribution 中对这两个头的说明)

Dead-lettered messages are re-published with publisher confirms turned on internally so, the dead-letter queues the messages eventually land on must confirm the messages before they are removed from the original queue. In other words, the publishing queue will not remove messages before the dead-letter queues acknowledge receiving them (see Confirms for details on the guarantees made). Note that, in the event of an unclean broker shutdown, the same message may be duplicated on both the original queue and on the dead-letter queues.
死信消息被重新 publish 时默认使用了 publisher confirm 机制,也就是说,保存死信的 queue 需要对这些消息进行 confirm ,才能使得消息被原始 queue 移除。换句话说,publish 到目标 queue 中的消息,在出现死信情况后,只有在死信 queue 对重新 publish 的消息进行了 confirm 之后,才会将消息移除(详情参 Confirms 的说明)。值得注意的是,如果处于 unclean 状态中的 broker 发生了 shutdown ,那么原始 queue 和死信 queue 中均可能出现重复的消息。

It is possible to form a cycle of dead-letter queues. For instance, this can happen when a queue dead-letters messages to the default exchange without specifiying a dead-letter routing key. Messages in such cycles (i.e. messages that reach the same queue twice) will be dropped if the entire cycle is due to message expiry.
利用死信 queue 构成一个循环结构是可能的一种使用情况。例如,当原始 queue 将消息按照死信处理,将其发送到默认 exchange 上,并且没有指定死信 routing key 的情况。在这个循环结构中的消息(也就是说,消息将会到达同一个 queue 两次)将会在消息自身设置的过期时间到达后被丢弃。

Dead-Lettered Messages
死信消息

Dead-lettering a message modifies its headers:
将消息处理为死信后,将会对其头部做如下修改:
  • the exchange name is replaced with that of the latest dead-letter exchange,
    exchange 名被替换成最新设置的 DLX 值,
  • the routing key may be replaced with that specified in a dead letter queue,
    routing key 可能被替换成声明死信 queue 时指定的值,
  • if the above happens, the CC header will also be removed, and
    如果上述情况发生了,CC 头将被移除,并且
  • the BCC header will be removed as per Sender-selected distribution.
    BCC 头将按照 Sender-selected distribution 中的要求被移除。
The dead-lettering process adds an array to the header of each dead-lettered message named x-death. This array contains an entry for each time the message was dead-lettered. Each such entry is a table that consists of several fields:
死信处理进程将会在每一条死信消息的头部添加一个名为 x-death 的数组。该数组中包含每一次消息被处理为死信时的 entry 。每一个这样的 entry 都是一个由下面各域构成的表:

  • queue - the name of the queue the message was in before it was dead-lettered, 
                  消息被作为死信处理前,应该进入的 queue 的名字,
  • reason - see below,
  • time - the date and time the message was dead lettered as a 64-bit AMQP format timestamp, 
              消息被处理为死信的日期和时间,表示为 64-bit 的 AMQP 格式时间戳,
  • exchange - the exchange the message was published to (note that this will be a dead letter exchange if the message is dead lettered multiple times), and 
                       消息应该 publish 到的 exchange 名(值得注意的是,该值在消息作为死信处理多次的情况下将会变为 DLX 的名字)
  • routing-keys - the routing keys (including CC keys but excluding BCC ones) the message was published with. 
                            消息被 publish 时使用的 routing key 值(包括 CC key 但不包括 BCC 值)。
  • original-expiration (if the message was dead-letterered due to per-message TTL) - the original expiration property of the message. The expiration property is removed from the message on dead-lettering in order to prevent it from expiring again in any queues it is routed to.
    初始过期时间(由于消息自身 TTL 到期而变为死信的情况) - 消息的原始过期时间属性。过期属性将会在消息被处理为死信时移除,以方式消息在死信 queue 中再次过期。
The reason is a name describing why the message was dead-lettered and is one of the following:
上面没有说明的 reason 值,实际上是一个描述为何消息作为死信处理的字段,可能为以下的值:
  • rejected - the message was rejected with requeue=false, 
                    消息被带有 requeue=false 的信令所拒绝,
  • expired - the TTL of the message expired; or 
                    消息 的 TTL 到期;或者
  • maxlen - the maximum allowed queue length was exceeded. 
                   保存消息的 queue 的长度达到了上限。
Note that the array is sorted most-recent-first, so the most recent dead-lettering will be recorded in the first entry.
值得注意的是,上面提到的数组是按照 most-recent-first 来排序的,故最新的死信消息将会被记录到第一个 entry 中。

© 著作权归作者所有

摩云飞
粉丝 375
博文 534
码字总数 952694
作品 0
徐汇
程序员
私信 提问
rabbitmq 实现延迟队列的两种方式

ps: 文章里面延迟队列=延时队列 什么是延迟队列 延迟队列存储的对象肯定是对应的延时消息,所谓”延时消息”是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者...

xiaomin0322
2018/04/20
370
0
rabbitmq延迟队列之php实现

延迟任务应用场景 场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。 场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单。 实...

china_lx1
2018/08/22
0
0
RabbitMQ一个简单可靠的方案(.Net Core实现)

前言   最近需要使用到消息队列相关技术,于是重新接触RabbitMQ。其中遇到了不少可靠性方面的问题,归纳了一下,大概有以下几种:   1. 临时异常,如数据库网络闪断、http请求临时失效等...

dotNET跨平台
2018/08/28
0
0
java B2B2C 仿淘宝电子商城系统-基于Rabbitmq实现延迟消息

预备知识 1.1 消息传递 首先我们知道消费者是从队列中获取消息的,那么消息是如何到达队列的? 当我们发送一条消息时,首先会发给交换器(exchange),交换器根据规则(路由键:routing key...

明理萝
04/02
9
1
Spring Boot与RabbitMQ结合实现延迟队列的示例

背景 何为延迟队列? 顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。 场景一:在订单系统中,一个用户下单之后通常有...

xiaomin0322
2018/05/11
670
0

没有更多内容

加载失败,请刷新页面

加载更多

解答二进制求和

思路:创建一个新的字符串,用于记录原两个字符串每位相加的结果。 1、因为是从左到右计算,所以要把字符串先进行反转,用reverse()方法。 2、字符串对齐,采用补零的方法。 3、计算的时候...

无名氏的程序员
11分钟前
1
0
JSONUtils

package com.demo.utils;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Tr......

任梁荣
11分钟前
4
1
在jest中配置typescript

测试是报错: Property 'assign' does not exist on type 'ObjectConstructor' NodeJS已经是最新版了,但道理不需要polyfill。 然后发现是typescript的lib没有"es2015.core",说明ts-jest没有......

linsk1998
12分钟前
2
0
Redis实现分布式文件夹锁

缘起 最近做一个项目,类似某度云盘,另外附加定制功能,本人负责云盘相关功能实现,这个项目跟云盘不同的是,以项目为分配权限的单位,同一个项目及子目录所有有权限的用户可以同时操作所有...

逸竹小站
21分钟前
2
0
Andorid SQLite数据库开发基础教程(2)

Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库。...

大学霸
41分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部