广告
返回顶部
首页 > 资讯 > 后端开发 > GO >​​​​​​​Golang实现RabbitMQ中死信队列几种情况
  • 207
分享到

​​​​​​​Golang实现RabbitMQ中死信队列几种情况

摘要

目录1、造成死信队列的主要原因2、操作逻辑图3、代码实战3.1 针对原因1:消费者超出时间未应答3.2 针对原因2:限制一定的长度3.3 针对原因3:消费者拒绝的消息回到死信队列中下

下面这段教程针对是你已经有一些基本的MQ的知识,比如说能够很清楚的理解queue、exchange等概念,如果你还不是很理解,我建议你先访问官网查看基本的教程。

1、造成死信队列的主要原因

  • 消费者超时未应答
  • 队列的容量有限
  • 消费者拒绝了的消息

2、操作逻辑图

3、代码实战

其实整体的思路就是分别创建一个nORMal_exchange、dead_exchange、normal_queue、dead_queue,然后将normal_exchange与normal_queue进行绑定,将dead_exchange与dead_queue进行绑定,这里比较关键的一个点在于说如何将normal_queue与dead_exchange进行绑定,这样才能将错误的消息传递过来。下面就是这段代码的关键。

// 声明一个normal队列
    _, err = ch.QueueDeclare(
        constant.NormalQueue,
        true,
        false,
        false,
        false,
        amqp.Table{
            //"x-message-ttl":             5000,                    // 指定过期时间
            //"x-max-length":              6,                        // 指定长度。超过这个长度的消息会发送到dead_exchange中
            "x-dead-letter-exchange":    constant.DeadExchange,    // 指定死信交换机
            "x-dead-letter-routing-key": constant.DeadRoutingKey,  // 指定死信routing-key
        })

3.1 针对原因1:消费者超出时间未应答

consumer1.Go

package day07

import (
    amqp "GitHub.com/RabbitMQ/amqp091-go"
    "log"
    "v1/utils"
)

type Constant struct {
    NormalExchange   string
    DeadExchange     string
    NormalQueue      string
    DeadQueue        string
    NormalRoutingKey string
    DeadRoutingKey   string
}

func Consumer1() {
    // 获取连接
    ch := utils.GetChannel()
    // 创建一个变量常量
    constant := Constant{
        NormalExchange:   "normal_exchange",
        DeadExchange:     "dead_exchange",
        NormalQueue:      "normal_queue",
        DeadQueue:        "dead_queue",
        NormalRoutingKey: "normal_key",
        DeadRoutingKey:   "dead_key",
    }
    // 声明normal交换机
    err := ch.ExchangeDeclare(
        constant.NormalExchange,
        amqp.ExchangeDirect,
        true,
        false,
        false,
        false,
        nil,
    )
    utils.FailOnError(err, "Failed to declare a normal exchange")
    // 声明一个dead交换机
    err = ch.ExchangeDeclare(
        constant.DeadExchange,
        amqp.ExchangeDirect,
        true,
        false,
        false,
        false,
        nil,
    )
    utils.FailOnError(err, "Failed to declare a dead exchange")

    // 声明一个normal队列
    _, err = ch.QueueDeclare(
        constant.NormalQueue,
        true,
        false,
        false,
        false,
        amqp.Table{
            "x-message-ttl": 5000, // 指定过期时间
            //"x-max-length":              6,
            "x-dead-letter-exchange":    constant.DeadExchange,   // 指定死信交换机
            "x-dead-letter-routing-key": constant.DeadRoutingKey, // 指定死信routing-key
        })
    utils.FailOnError(err, "Failed to declare a normal queue")
    // 声明一个dead队列:注意不要给死信队列设置消息时间,否者死信队列里面的信息会再次过期
    _, err = ch.QueueDeclare(
        constant.DeadQueue,
        true,
        false,
        false,
        false,
        nil)
    utils.FailOnError(err, "Failed to declare a dead queue")

    // 将normal_exchange与normal_queue进行绑定
    err = ch.QueueBind(constant.NormalQueue, constant.NormalRoutingKey, constant.NormalExchange, false, nil)
    utils.FailOnError(err, "Failed to binding normal_exchange with normal_queue")
    // 将dead_exchange与dead_queue进行绑定
    err = ch.QueueBind(constant.DeadQueue, constant.DeadRoutingKey, constant.DeadExchange, false, nil)
    utils.FailOnError(err, "Failed to binding dead_exchange with dead_queue")

    // 消费消息
    msgs, err := ch.Consume(constant.NormalQueue,
        "",
        false, // 这个地方一定要关闭自动应答
        false,
        false,
        false,
        nil)
    utils.FailOnError(err, "Failed to consume in Consumer1")

    var forever chan struct{}

    go func() {
        for d := range msgs {
            if err := d.Reject(false); err != nil {
                utils.FailOnError(err, "Failed to Reject a message")
            }
        }
    }()
    log.Printf(" [*] Waiting for logs. To exit press CTRL+C")

    <-forever
}

consumer2.go

package day07

import (
    amqp "github.com/rabbitmq/amqp091-go"
    "log"
    "v1/utils"
)

func Consumer2() {
    // 拿取信道
    ch := utils.GetChannel()

    // 声明一个交换机
    err := ch.ExchangeDeclare(
        "dead_exchange",
        amqp.ExchangeDirect,
        true,
        false,
        false,
        false,
        nil)
    utils.FailOnError(err, "Failed to Declare a exchange")

    // 接收消息的应答
    msgs, err := ch.Consume("dead_queue",
        "",
        false,
        false,
        false,
        false,
        nil,
    )

    var forever chan struct{}
    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

}

produce.go

package day07

import (
    "context"
    amqp "github.com/rabbitmq/amqp091-go"
    "strconv"
    "time"
    "v1/utils"
)

func Produce() {
    // 获取信道
    ch := utils.GetChannel()
    // 声明一个交换机
    err := ch.ExchangeDeclare(
        "normal_exchange",
        amqp.ExchangeDirect,
        true,
        false,
        false,
        false,
        nil)
    utils.FailOnError(err, "Failed to declare a exchange")
    ctx, cancer := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancer()

    // 发送了10条消息
    for i := 0; i < 10; i++ {
        msg := "Info:" + strconv.Itoa(i)
        ch.PublishWithContext(ctx,
            "normal_exchange",
            "normal_key",
            false,
            false,
            amqp.Publishing{
                ContentType: "text/plain",
                Body:        []byte(msg),
            })
    }
}

3.2 针对原因2:限制一定的长度

只需要改变consumer1.go中的对normal_queue的声明

// 声明一个normal队列
    _, err = ch.QueueDeclare(
        constant.NormalQueue,
        true,
        false,
        false,
        false,
        amqp.Table{
            //"x-message-ttl": 5000, // 指定过期时间
            "x-max-length":              6,
            "x-dead-letter-exchange":    constant.DeadExchange,   // 指定死信交换机
            "x-dead-letter-routing-key": constant.DeadRoutingKey, // 指定死信routing-key
        })

3.3 针对原因3:消费者拒绝的消息回到死信队列中

这里需要完成两点工作

工作1:需要在consumer1中作出拒绝的操作

go func() {
        for d := range msgs {
            if err := d.Reject(false); err != nil {
                utils.FailOnError(err, "Failed to Reject a message")
            }
        }
    }()

工作2:如果你consume的时候开启了自动应答一定要关闭

// 消费消息
    msgs, err := ch.Consume(constant.NormalQueue,
        "",
        false, // 这个地方一定要关闭自动应答
        false,
        false,
        false,
        nil)

其他的部分不需要改变,按照问题1中的设计即可。

到此这篇关于golang实现RabbitMQ中死信队列几种情况的文章就介绍到这了,更多相关​​​​​​​Golang RabbitMQ死信队列内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: ​​​​​​​Golang实现RabbitMQ中死信队列几种情况

本文链接: https://www.lsjlt.com/news/197947.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作