RabbitMQ-死信队列DLX
一,死信队列
利用DLX, 当消息在一个队列中变成死信(dead message)之后, 它能被重新publish到另一个Exchange, 这个Exchange就是DLX。
DLX也是一个正常的Exchange, 和一般的Exchange没有区别, 它能在任何队列上被指定, 实际上就是设置某个队列的属性为死信队列。当这个队列中有死信时, RabbitMQ就会自动将这个消息重新发布到设置的Exchange上去, 进而被路由到另一个队列
可以监听这个队列中消息做相应的处理。
二,消息变成死信的几种情况
(1)消息被拒绝(basic.reject/basic.nack) 并且requeue重回队列设置成false
(2)消息TTL过期
(3)队列达到最大长度
三,死信队列的设置
对于任何给定队列,DLX可以由使用队列参数的客户端定义,也可以 在使用策略的服务器中定义。在策略和参数都指定DLX的情况下,参数中指定的那个会覆盖策略中指定的那个。
建议使用策略进行配置,因为它允许不涉及应用程序重新部署的DLX重新配置。
1,使用策略配置
要使用策略指定DLX,请将“dead-letter-exchange”键添加到策略定义中。例如:
这将DLX“my-dlx”应用于所有队列。类似地,可以通过向策略添加密钥“dead-letter-routing-key”来指定显式路由密钥。
2,使用可选队列参数配置
要为队列设置死信交换,需要在声明队列时指定可选的x-dead-letter-exchange参数,该值必须是同一虚拟主机中的交换名称。c++代码演示如下:
首先我们需要创建一个正常的队列:
amqp_queue_declare_ok_t *res = amqp_queue_declare(
m_connectState,
channel_id,
amqp_cstring_bytes(queue.m_name.c_str()),
queue.m_bPassive, /*passive*/ //检验队列是否存在(同exchange中的passive属性)
queue.m_durable, /*durable*/ //队列是否持久化(即使mq服务重启也会存在)
queue.m_bExclusive, /*exclusive*/ //是否是专用队列(当前连接不在时,队列是否删除)
queue.m_bAutoDelete,/*auto_delete*/ //是否自动删除(什么时候删除?。。。)
amqp_table);
amqp_rpc_reply_t rpc_reply = amqp_get_rpc_reply(m_connectState);
if (0 != GetErrorText(rpc_reply, "amqp_queue_declare", ErrorReturn))
{
return -1;
}
函数amqp_queue_declare的最后一个参数类型是amqp_table_t,结构声明如下:
typedef struct amqp_table_t_ {
int num_entries; /**< length of entries array */
struct amqp_table_entry_t_ *entries; /**< an array of table entries */
} amqp_table_t;
amqp_table_t是一个存储数组指针的结构体,其中的指针指向的是amqp_table_entry_t结构,声明如下:
typedef struct amqp_table_entry_t_ {
amqp_bytes_t key; /**< the table entry key. Its a null-terminated UTF-8
* string, with a maximum size of 128 bytes */
amqp_field_value_t value; /**< the table entry values */
} amqp_table_entry_t;
简单理解,它就是一个key,value形式的结构体,其中key是数据类型,value是具体的数据内容,我们需要填充如下:
//填充x_death
int nTableNum = 3;
amqp_table_entry_t *pTable = (amqp_table_entry_t*)malloc(sizeof(amqp_table_entry_t) * nTableNum);
{
pTable[0].key = amqp_cstring_bytes("x-dead-letter-exchange");
pTable[0].value.value.bytes = amqp_cstring_bytes("dlx.default_message_push_exchange");
pTable[0].value.kind = AMQP_FIELD_KIND_UTF8;
pTable[1].key = amqp_cstring_bytes("x-dead-letter-routing-key");
pTable[1].value.value.bytes = amqp_cstring_bytes("#");;
pTable[1].value.kind = AMQP_FIELD_KIND_UTF8;
pTable[2].key = amqp_cstring_bytes("x-max-length");
pTable[2].value.value.u16 = 200;
pTable[2].value.kind = AMQP_FIELD_KIND_U16;
}
amqp_table.num_entries = 3;
amqp_table.entries = pTable ;
amqp_table_t填充完毕,创建新队列的时候传参进去,那么就相当于给该正常队列绑定了一个死信交换机,当出现上面讲述的三种情况时,消息将会进入死信队列。请注意,在声明队列时不必声明交换,但是当消息需要使用死信时它应该存在; 如果它丢失了,消息将被静默删除。
因此,我们还需要再创建对应的死信交换机和死信队列,并通过x-dead-letter-routing-key将它们绑定在一起。简单理解:死信交换机和死信队列也可以当做正常的队列来进行声明,绑定和消费。
如果x-dead-letter-routing-key没有设置,将使用消息自己原本的routing_key值。
3,通过web管理界面设置死信队列
RabbitMQ服务部署后,可以通过15672端口直接访问mq的web管理界面,我们同样地也可以在这上面进行正常队列的死信队列创建和绑定操作,具体操作大家可以参照这一篇博客RabbitMQ管理界面配置死信队列
四,死信队列的优点
1,使用死信队列可以缓解生产者速度快,消费者速度慢的问题。
2,通过死信队列可以间接实现延迟消息的处理:正常的消息不设置延时,特殊消息设置延时,指定的消费者去消费对应的死信队列。
3,死信队列从另一个角度来说可以提现RabbitMQ的可靠性,异常情况下的消息并不会丢失,而是进入到死信队列中,再由消费者去消费。
参考文章:
1,https://www.rabbitmq.com/dlx.html
2,https://blog.csdn.net/love905661433/article/details/85449191
3,https://blog.csdn.net/zhanghan18333611647/article/details/79519085