RabbitMQ 入门与 Go 语言实践
一、RabbitMQ 简介
RabbitMQ 是一个基于 AMQP(Advanced Message Queuing Protocol) 的 开源消息队列中间件 ,由 Erlang 语言开发,具有高可用、高可靠、易扩展等特点。
RabbitMQ 的核心价值是 解耦、异步、削峰填谷。
1.1 为什么要用消息队列
在微服务或高并发系统中,直接同步调用会导致以下问题:
- 系统之间强耦合,难以扩展。
- 高并发时容易压垮数据库。
- 请求耗时长,用户体验差。
RabbitMQ 提供了解决方案:
- 异步处理 → 提升响应速度
- 系统解耦 → 让服务之间更灵活
- 削峰填谷 → 防止高并发压垮后端
- 可靠传递 → 确保消息不丢失
二、RabbitMQ 架构与工作原理
RabbitMQ 的核心是 生产者-消费者模型 ,但中间多了一层 Exchange(交换机),它负责接收消息并根据规则路由到不同队列。
2.1 RabbitMQ 架构图
Producer → Exchange → Queue → Consumer
↑
Routing Key
2.2 RabbitMQ 工作流程
- 生产者:发送消息给 Exchange。
- 交换机(Exchange):根据绑定规则,将消息分发到队列。
- 队列(Queue):存储消息。
- 消费者(Consumer):从队列中取出消息,进行处理。
三、RabbitMQ 核心概念
3.1 Broker
RabbitMQ 服务器本身,负责接收和转发消息。
3.2 Connection / Channel
- Connection :客户端与 RabbitMQ 之间的 TCP 连接。
- Channel:在一个 Connection 上可创建多个 Channel,提高并发性能。
⚡ 建议:复用一个 Connection,开多个 Channel,而不是频繁创建连接。
3.3 Exchange(交换机)
四种类型:
类型 | 说明 | 应用场景 |
---|---|---|
Direct | 精确匹配路由键 | 单播 |
Fanout | 广播所有绑定队列 | 广播消息 |
Topic | 通配符匹配路由键 | 多维度订阅 |
Headers | 根据消息头路由 | 比较少用 |
3.4 Queue(队列)
消息最终存储的地方,消费者从队列取数据。
3.5 Routing Key(路由键)
生产者发送消息时指定的关键字,用于 Exchange 匹配目标队列。
3.6 Binding(绑定)
建立 Exchange 和 Queue 的绑定关系,定义消息分发规则。
四、RabbitMQ 安装与启动
4.1 使用 Docker(推荐)
bash
docker run -d \
--name rabbitmq \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=123456 \
-p 5672:5672 \
-p 15672:15672 \
rabbitmq:3.12-management
- 5672:AMQP 协议端口
- 15672:管理控制台端口
4.2 登录管理界面
- URL:http://localhost:15672
- 用户名:admin
- 密码:123456
4.3 管理界面常用功能
- Queues → 查看队列消息
- Exchanges → 管理交换机
- Connections → 查看连接
- Channels → 查看信道
- Admin → 用户管理与权限控制
五、Go 语言操作 RabbitMQ
我们使用官方推荐库:
bash
go get github.com/rabbitmq/amqp091-go
5.1 创建连接与通道
go
conn, err := amqp.Dial("amqp://admin:123456@localhost:5672/")
if err != nil {
log.Fatalf("连接失败: %v", err)
}
defer conn.Close()
ch, err := conn.Channel()
if err != nil {
log.Fatalf("打开通道失败: %v", err)
}
defer ch.Close()
5.2 生产者(Producer)
go
q, err := ch.QueueDeclare(
"order_queue", // 队列名
true, // 持久化
false, // 自动删除
false, // 独占
false, // no-wait
nil, // 额外参数
)
body := "订单创建成功!"
err = ch.Publish(
"", // exchange
q.Name, // routing key
false,
false,
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body),
},
)
if err != nil {
log.Fatalf("发送失败: %v", err)
}
log.Printf("消息已发送: %s", body)
5.3 消费者(Consumer)
go
msgs, err := ch.Consume(
"order_queue",
"",
true, // 自动应答
false,
false,
false,
nil,
)
if err != nil {
log.Fatalf("注册消费者失败: %v", err)
}
log.Println("等待接收消息...")
for msg := range msgs {
log.Printf("收到消息: %s", msg.Body)
}
六、死信队列(DLX)详解
在 RabbitMQ 中,死信队列 (Dead Letter Queue,简称 DLQ)是一种特殊的队列,主要用于存放那些 无法被正常消费 的消息。
通过配置 死信交换机(Dead Letter Exchange,DLX),我们可以将处理失败、超时或被拒绝的消息转发到专门的队列中,方便后续分析或重试。
6.1 为什么需要死信队列
在实际生产环境中,可能会出现以下问题:
- 消费者业务逻辑异常,导致消息无法消费
- 消息超时(TTL 到期)
- 队列达到最大长度,新的消息无法进入
- 消费者手动拒绝消息,并选择不重新入队
如果没有 DLX,这些异常消息会被直接丢弃,造成数据丢失,影响业务可靠性。
DLX 的核心作用 :"兜底",收集无法正常处理的消息。
6.2 哪些情况会进入 DLX
场景 | 触发条件 | 是否进入 DLX |
---|---|---|
消息被拒绝 | msg.Nack(requeue=false) 或 msg.Reject(false) |
✅ 会进入 |
消息过期(TTL) | 队列或消息设置了过期时间,到期未被消费 | ✅ 会进入 |
队列已满 | 队列达到 x-max-length 限制 |
✅ 会进入 |
消费者宕机 | 没有 Ack,消息重新投递,重试失败 | ✅ 会进入 |
正常消费成功 | msg.Ack() |
❌ 不会进入 |
6.3 DLX 架构图
[Producer]
│
▼
┌──────────────┐
│ 正常交换机 │
└─────┬────────┘
│
┌─────▼────────┐
│ 正常队列 │
│ x-dead-letter │
└─────┬────────┘
│
┌─────▼────────┐
│ 死信交换机 │
└─────┬────────┘
│
┌─────▼────────┐
│ 死信队列 │
└──────────────┘
- 正常队列 → 配置了 x-dead-letter-exchange
- 死信交换机 → 接收异常消息
- 死信队列 → 存放异常消息,便于后续处理
6.4 死信队列配置步骤
① 声明死信交换机
go
dlx, _ := ch.ExchangeDeclare(
"dlx.exchange", // 死信交换机名称
"fanout", // 类型:fanout 广播
true, // 持久化
false, // 自动删除
false,
false,
nil,
)
② 声明正常队列并绑定 DLX
给正常队列绑定一个 死信交换机,当消息无法处理时自动转发。
go
q, _ := ch.QueueDeclare(
"order_queue", // 正常队列
true,
false,
false,
false,
amqp.Table{
// 配置死信交换机
"x-dead-letter-exchange": "dlx.exchange",
},
)
③ 声明死信队列并绑定 DLX
go
dlq, _ := ch.QueueDeclare(
"order_dlx", // 死信队列
true,
false,
false,
false,
nil,
)
ch.QueueBind(
dlq.Name, // 队列名
"", // routing key
"dlx.exchange", // 死信交换机
false,
nil,
)
④ 消费者示例
go
msgs, _ := ch.Consume(
"order_queue", // 订阅正常队列
"",
false, // 关闭自动应答,手动 Ack
false,
false,
false,
nil,
)
for msg := range msgs {
success := process(msg.Body)
if success {
msg.Ack(false) // 消费成功
} else {
msg.Nack(false, false) // 消费失败,不重新入队 → 进入 DLX
}
}
6.5 死信队列的好处
✅ 集中管理异常消息
将处理失败的消息统一收集,便于分析问题。
✅ 提高系统可靠性
避免消息直接丢失,保证数据完整性。
✅ 支持后续补偿机制
可以手动或自动从死信队列重新消费,进行业务补偿。
6.6 实际应用场景
场景 1:延迟队列
利用 DLX + TTL,可以实现订单超时自动取消。
- 给正常队列设置 TTL,比如 30 分钟
- 到期未支付的订单消息 → 自动进入 DLX
- DLX 绑定的死信队列由"取消订单服务"消费
场景 2:异常消息隔离
在高并发秒杀场景中,如果某些消息格式异常,可将其拒绝并丢入 DLX,避免影响主业务队列。
6.7 总结
-
DLX 是 RabbitMQ 保证消息可靠性的核心机制之一
-
主要用于处理异常消息:拒绝、过期、队列满
-
通过配置
x-dead-letter-exchange
实现 -
搭配 TTL、Nack、限流策略,可以实现:
- 延迟队列
- 异常隔离
- 失败重试