死信队列:
死信队列用于处理无法被正常消费的消息。
一条消息初次消费失败会被重试消费,若重试次数达到最大值(默认16次,在客户端可配置)时,依然消费失败,则其将被投递到该消费者对应的特殊队列(即死信队列)中,这种消息被称为死信消息。
应用场景:
为了保证订单业务的消息数据不丢失,需要使用到RabbitMQ的死信队列机制,当消息出现异常时,将消息投入死信队列中。
用户商城下单成功点击去支付后在指定时间内未支付时自动失效
死信的原因:
- 消息TTL过期
- 队列达到最大长度,即队列已满
- 消息被拒,并且不放回
实战
- 业务队列声明时,设置args,包括exchange、routing-key、ttl
const (
NormalExchange = "normalExchange"
DeadExchange = "deadExchange"
NormalQueue = "normalQueue"
DeadQueue = "deadQueue"
)
func main() {
channel, _ := utils.GetRabbitMQChannel()
_ = channel.ExchangeDeclare(NormalExchange, "direct", false, false, false, false, nil)
_ = channel.ExchangeDeclare(DeadExchange, "direct", false, false, false, false, nil)
args := amqp.Table{}
args["x-dead-letter-exchange"] = DeadExchange
args["x-dead-letter-routing-key"] = "deadMsg"
args["x-message-ttl"] = 10000
nqueue, _ := channel.QueueDeclare(NormalQueue, false, false, false, false, args)
dqueue, _ := channel.QueueDeclare(DeadQueue, false, false, false, false, nil)
_ = channel.QueueBind(nqueue.Name, "normalMsg", NormalExchange, false, nil)
_ = channel.QueueBind(dqueue.Name, "deadMsg", DeadExchange, false, nil)
msgs, _ := channel.Consume(nqueue.Name, "", false, false, false, false, nil)
forever := make(chan bool)
go func() {
for d := range msgs {
log.Printf(" [x] %s", d.Body)
d.Ack(false)
}
}()
log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
<-forever
}
- 消息生产者设置消息过期时间,消息过期后就变成死信,进入死信队列
func main() {
channel, _ := utils.GetRabbitMQChannel()
_ = channel.ExchangeDeclare(NormalExchange, "direct", false, false, false, false, nil)
_ := channel.Publish(NormalExchange, "normalMsg", false, false,
amqp.Publishing{
Expiration: "10000",
ContentType: "text/plain",
Body: []byte("hello rabbit"),
})
}
- 业务队列声明时,设置队列最大长度,当队列满了后,再往队列发送消息就会进入死信队列
args["x-max-length"] = 10
- 消费者拒绝
go func() {
for d := range msgs {
log.Printf(" [x] %s", d.Body)
d.Reject(false)
}
}()