RabbitMQ 基础与实战:核心概念与 Hello World
各位同学,今天我们来聊聊消息队列。说实话,我在做后端开发的头两年,一直觉得消息队列是个「高大上」的东西。直到有一次,我负责的系统在双十一期间被瞬间流量打垮,数据库连接池直接爆掉……嗯,从那以后,我再也不敢轻视消息队列了。
RabbitMQ 是我个人用得最多的消息中间件。它稳定、成熟,社区活跃。今天这一章,我们就把它彻底搞明白。
RabbitMQ 核心概念:三驾马车
RabbitMQ 的核心,说白了就三个东西:Exchange(交换机)、Queue(队列)、Binding(绑定)。你想想看,消息从生产者发出,到消费者接收,中间经历了什么?
生产者把消息发给 Exchange,Exchange 根据 Binding 规则,把消息路由到对应的 Queue,消费者再从 Queue 里取消息。就这么简单。
核心流程:
Producer → Exchange → (Binding) → Queue → Consumer
我在项目中遇到过不少新手,上来就直接往 Queue 里发消息,跳过了 Exchange。这其实是不对的。RabbitMQ 的设计哲学就是:消息永远先到 Exchange,再由它决定去哪。
Exchange(交换机)
Exchange 是消息的「路由器」。它不存消息,只负责转发。RabbitMQ 有四种 Exchange 类型:
| 类型 | 路由规则 | 典型场景 |
|---|---|---|
| Direct | 完全匹配 Routing Key | 点对点通信 |
| Topic | 通配符匹配 Routing Key | 按主题分发 |
| Fanout | 广播给所有绑定的 Queue | 发布/订阅 |
| Headers | 匹配消息的 Header 属性 | 复杂路由 |
我个人习惯,90% 的场景用 Direct 或 Topic 就够了。Fanout 适合做广播,比如配置更新通知。Headers 用得少,性能也差一些,能不碰就不碰。
Queue(队列)
Queue 是消息的「暂存区」。消息到了 Queue 之后,就等着消费者来取。Queue 有几个关键属性:
- Durable:持久化。队列和消息都会写入磁盘,RabbitMQ 重启后不丢失。我建议生产环境一律设为 true。
- Exclusive:排他。只被一个连接使用,连接断开自动删除。适合临时队列。
- Auto-delete:自动删除。最后一个消费者断开后删除队列。
小提示:我曾经在生产环境踩过一个坑——队列没设 Durable,结果 RabbitMQ 重启后队列全没了,消息全部丢失。从那以后,我所有队列都加上了 durable=true。
Binding(绑定)
Binding 就是 Exchange 和 Queue 之间的「连接线」。它定义了 Exchange 把消息发给哪个 Queue,以及用什么规则匹配。
Binding 的核心是 Routing Key。比如你有一个 Direct 类型的 Exchange,Binding 时指定了 Routing Key 为 "order.create",那么只有携带 "order.create" 这个 Routing Key 的消息才会被路由到这个 Queue。
安装与配置
安装 RabbitMQ 其实很简单。我推荐用 Docker,省心省力。
# 拉取镜像并启动
docker run -d --name rabbitmq \
-p 5672:5672 -p 15672:15672 \
rabbitmq:3.12-management
5672 是 AMQP 协议端口,15672 是管理控制台端口。启动后,浏览器访问 http://localhost:15672,默认用户名密码都是 guest。
注意:生产环境千万别用 guest 账号。guest 只能在 localhost 登录。我建议创建一个专用用户,并设置强密码。
如果你不想用 Docker,直接安装也很简单:
# Ubuntu / Debian
sudo apt-get install rabbitmq-server
# macOS
brew install rabbitmq
安装完成后,启动服务:
sudo systemctl start rabbitmq-server
sudo systemctl enable rabbitmq-server # 开机自启
Java 客户端连接与 Hello World
Java 客户端我用的是官方的 amqp-client。先加依赖:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.20.0</version>
</dependency>
然后写一个最简单的生产者:
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
public class Send {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
// 1. 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
// 2. 创建连接和通道
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// 3. 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 4. 发送消息
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
}
}
}
消费者也很简单:
import com.rabbitmq.client.*;
public class Recv {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages...");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
}
}
先运行 Send,再运行 Recv,你就能看到消息被成功发送和接收了。
Python 客户端连接与 Hello World
Python 客户端我用 pika。先安装:
pip install pika
生产者代码:
import pika
# 1. 建立连接
connection = pika.BlockingConnection(
pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 2. 声明队列
channel.queue_declare(queue='hello')
# 3. 发送消息
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()
消费者代码:
import pika
def callback(ch, method, properties, body):
print(f" [x] Received {body}")
connection = pika.BlockingConnection(
pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_consume(queue='hello',
auto_ack=True,
on_message_callback=callback)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
Python 的代码比 Java 简洁不少。不过要注意,pika 的 BlockingConnection 是同步的,生产环境建议用异步的 SelectConnection。
知识体系图
下面这张图,帮你把今天讲的内容串起来:
避坑指南
最后,分享几个我踩过的坑:
- 连接泄漏:我曾经在循环里创建 Connection 但不关闭,结果 RabbitMQ 的连接数飙到几千,直接 OOM。记住:Connection 是长连接,一个应用一个就够了。
- 消息丢失:默认情况下,RabbitMQ 的消息是存在内存里的。一旦宕机,全丢。生产环境一定要开启持久化(Delivery Mode = 2)。
- 队列名重复:不同业务用同一个队列名,会导致消息混乱。我习惯用「业务名_队列名」的命名方式,比如
order_create_queue。
我的建议:刚开始学 RabbitMQ,别急着搞复杂路由。先用 Direct Exchange + 一个 Queue 跑通 Hello World,再慢慢加功能。一口吃不成胖子,消息队列也一样。
好了,这一章的内容就到这里。RabbitMQ 的核心概念、安装配置、Java 和 Python 的 Hello World,你都应该能跑通了。下一章我们会深入消息的确认机制和持久化策略,到时候再聊。