在Go中迅速使用RabbitMQ

2024-09-05 19:44
文章标签 go 使用 rabbitmq 迅速

本文主要是介绍在Go中迅速使用RabbitMQ,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1 认识
    • 1.1 MQ分类
    • 1.2 安装
    • 1.3 基本流程
  • 2 [Work模型](https://www.rabbitmq.com/tutorials/tutorial-two-go#preparation)
  • 3 交换机
    • 3.1 fanout
    • 3.2 direct
    • 3.3 [topic](https://www.rabbitmq.com/tutorials/tutorial-five-go)
  • 4 Golang创建交换机/队列/Publish/Consume/Bind
  • 5 可靠性
    • 5.1 生产者可靠性
    • 5.2 MQ可靠性
      • 5.2.1 Lazy Queue
    • 5.3 消费者可靠性
    • 5.4 业务幂等性
    • 5.4 Golang实现可靠性
      • 1. 确保消息生产者的可靠性
      • 2. 确保消息队列的可靠性
      • 3. 确保消息消费者的可靠性
      • 4. 容错处理
  • 6 延迟消息
    • 6.1 死信交换机
    • 6.2 延迟消息插件
      • 6.2.1 安装
      • 6.2.2 使用
      • 6.2.3 应用场景

  • 为什么要使用消息队列

image-20240903160417835

1 认识

1.1 MQ分类

  • 有Broker

    • 重Topic —— 在整个broker中,依据topic来进行消息中转。在重topic的MQ中必然需要topic —— kafka
    • 轻Topic —— topic只是一种中转模式 —— rabbitMQ
  • 无Broker

1.2 安装

# latest RabbitMQ 3.13
docker run \-e RABBITMQ_DEFAULT_USER=dusong \  #默认账号和密码均为:guest-e RABBITMQ_DEFAULT_PASS=123123 \-d \  #detached mode-v mq-plugins:/plugins \   #插件挂载--rm \--name rabbitmq \-p 5672:5672 \    #消息通信端口-p 15672:15672 \  #管理界面端口rabbitmq:3.13-management

1.3 基本流程

image-20240904110326213

  • exchange只能转发消息,不能存储消息
  • 通过bind将queue绑定到exchange

2 Work模型

  • 多个消费者绑定到一个队列

  • 同一个消息只会被一个消费者处理

  • 通过设置prefetch来控制消费者预取的消息数量(不设置默认平均平均分配)

    image-20240904144344585

    err = ch.Qos(1,     // prefetch count0,     // prefetch sizefalse, // global
    )
    

3 交换机

3.1 fanout

fanout类型的交换机会将消息转发给所有绑定到改交换机的队列

3.2 direct

image-20240904151234823

err = ch.ExchangeDeclare("logs_direct", // name"direct",      // typetrue,          // durablefalse,         // auto-deletedfalse,         // internalfalse,         // no-waitnil,           // arguments
)
failOnError(err, "Failed to declare an exchange")ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()body := bodyFrom(os.Args)
err = ch.PublishWithContext(ctx,"logs_direct",         // exchange"log", // routing keyfalse, // mandatoryfalse, // immediateamqp.Publishing{ContentType: "text/plain",Body:        []byte(body),
})

3.3 topic

image-20240904151944421

4 Golang创建交换机/队列/Publish/Consume/Bind

  • 创建交换机

    err = ch.ExchangeDeclare("logs_direct", // name"direct",      // typetrue,          // durablefalse,         // auto-deletedfalse,         // internalfalse,         // no-waitnil,           // arguments
    )
    
  • 创建队列

    q, err := ch.QueueDeclare("hello", // namefalse,   // durable(是否持久化)false,   // delete when unusedfalse,   // exclusivefalse,   // no-waitnil,     // arguments
    )
    
  • 绑定

    err = ch.QueueBind(q.Name,        // queue name"log",             // routing key"logs_direct", // exchangefalse,nil
    )
    
  • 发送

    body := "this is log"
    err = ch.PublishWithContext(ctx,"logs_direct",         // exchange"log", // routing keyfalse,                 // mandatoryfalse,                 // immediateamqp.Publishing{ContentType: "text/plain",Body:        []byte(body),})
    
  • 接收

    msgs, err := ch.Consume(q.Name, // queue"",     // consumertrue,   // auto ackfalse,  // exclusivefalse,  // no localfalse,  // no waitnil,    // args
    )
    

5 可靠性

5.1 生产者可靠性

  • 生产者重连

  • 生产者确认(ack)

5.2 MQ可靠性

  • 交换机/队列持久化
  • 消息持久化

5.2.1 Lazy Queue

image-20240904172117264

image-20240904163818387

5.3 消费者可靠性

  • 消费者确认机制

    image-20240904172521990

5.4 业务幂等性

  • 消费者因为保证可靠性可能消费业务多次,因此需要保证业务幂等性
  1. 给消息加上uuid
  2. 在业务逻辑上做修改

5.4 Golang实现可靠性

在使用 RabbitMQ 的 Go 应用程序中,要确保消息的可靠性,通常需要从以下几个方面入手:

1. 确保消息生产者的可靠性

  • 消息确认(Publisher Confirms): 开启 RabbitMQ 的发布确认模式。通过调用 Channel.Confirm() 方法,让 RabbitMQ 服务器在成功接收并持久化消息后向生产者发送确认。这样可以确保生产者知道消息已被可靠接收。

    ch.Confirm(false) // 启用发布确认模式
    confirm := ch.NotifyPublish(make(chan amqp.Confirmation, 1))// 发布消息
    err = ch.Publish(exchange, routingKey, mandatory, immediate, msg)
    if err != nil {// 处理发布失败的情况
    }select {
    case confirmed := <-confirm:if confirmed.Ack {fmt.Println("消息已确认")} else {fmt.Println("消息未确认")}
    case <-time.After(time.Second * 5):fmt.Println("消息确认超时")
    }
    
  • 消息持久化(Message Durability): 将消息标记为持久化,以确保即使 RabbitMQ 服务器重启,消息也不会丢失。通过设置 DeliveryModeamqp.Persistent 来实现:

    msg := amqp.Publishing{DeliveryMode: amqp.Persistent,ContentType:  "text/plain",Body:         []byte("Hello, RabbitMQ!"),
    }
    

2. 确保消息队列的可靠性

  • 队列持久化(Queue Durability): 创建队列时,将其声明为持久化队列。这样即使 RabbitMQ 服务器重启,队列依然存在。

    _, err = ch.QueueDeclare("my_queue",  // 队列名true,        // 是否持久化false,       // 是否自动删除false,       // 是否排他false,       // 是否阻塞nil,         // 其他参数
    )
    if err != nil {log.Fatalf("Failed to declare a queue: %s", err)
    }
    

3. 确保消息消费者的可靠性

  • 手动确认(Manual Acknowledgment): 消费者手动确认接收到的消息。这样只有在消息成功处理后,RabbitMQ 才会将其从队列中移除。如果消费者没有确认消息且发生故障,RabbitMQ 会将消息重新投递。

    msgs, err := ch.Consume("my_queue", // 队列名"",         // 消费者标识false,      // 自动确认false,      // 是否排他false,      // 是否阻塞false,      // 是否在同一个连接上消费nil,        // 其他参数
    )
    if err != nil {log.Fatalf("Failed to register a consumer: %s", err)
    }for d := range msgs {// 处理消息fmt.Printf("Received a message: %s", d.Body)// 手动确认d.Ack(false)
    }
    
  • QoS(Quality of Service): 设置消费者的 QoS 参数,例如 prefetch_count,确保消费者不会一次处理太多消息,从而导致过载。

    err = ch.Qos(1,    // 每次处理一条消息0,    // 消息大小限制(不限制)false, // 是否应用于整个通道
    )
    if err != nil {log.Fatalf("Failed to set QoS: %s", err)
    }
    

4. 容错处理

  • 重试机制: 在生产者和消费者中实现重试机制,例如使用带有指数回退的重试逻辑,以应对 RabbitMQ 不可用或网络波动的情况。

  • 死信队列(DLX): 配置死信队列,将处理失败的消息路由到指定的死信队列,方便后续分析和处理。

通过这些措施,可以有效提高使用 RabbitMQ 时的消息可靠性。

6 延迟消息

6.1 死信交换机

image-20240905145924200

6.2 延迟消息插件

6.2.1 安装

  1. https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.13.0/rabbitmq_delayed_message_exchange-3.13.0.ez

  2. 将插件放在该目录

    image-20240905153455222

  3. docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq-delayed-message-exchange

6.2.2 使用

 // 3. 声明延迟交换机err = ch.ExchangeDeclare("delay_exchange",               // 交换机名称"x-delayed-message",            // 交换机类型true,                           // 是否持久化false,                          // 是否自动删除false,                          // 是否内部使用false,                          // 是否等待amqp.Table{"x-delayed-type": "direct"}, // 交换机类型的设置)failOnError(err, "Failed to declare an exchange")// 4. 发送消息body := "Hello World with delay"err = ch.Publish("delay_exchange", // 交换机名称"routing_key",    // 路由键false,            // 是否强制发送false,            // 是否立即发送amqp.Publishing{ContentType: "text/plain",Body:        []byte(body),Headers: amqp.Table{"x-delay": int32(5000), // 延迟时间,单位为毫秒 (5秒延迟)},})

6.2.3 应用场景

  • 消息内部维护一个计时器,延迟消息对CPU的消耗较高,适用于延迟时间较短的场景

image-20240905155732697
false, // 是否立即发送
amqp.Publishing{
ContentType: “text/plain”,
Body: []byte(body),
Headers: amqp.Table{
“x-delay”: int32(5000), // 延迟时间,单位为毫秒 (5秒延迟)
},
})


### 6.2.3 应用场景- 消息内部维护一个计时器,延迟消息对CPU的消耗较高,适用于延迟时间较短的场景[外链图片转存中...(img-eA0QMPnx-1725527666228)]

这篇关于在Go中迅速使用RabbitMQ的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139893

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud