4、RabbitMQ入门:核心概念与安装配置
好,咱们开始聊 RabbitMQ。说实话,消息队列这块,RabbitMQ 是我个人用得最多的中间件之一。它稳定、成熟,社区活跃,非常适合游戏服务器这种对可靠性要求高的场景。
这一章,咱们先把 RabbitMQ 的底子打牢。我会带你搞懂三个核心概念:Exchange、Queue、Binding。然后手把手把环境搭起来。嗯,别急,一步步来。
4.1 核心概念:Exchange、Queue、Binding
这三个东西,说白了就是 RabbitMQ 的骨架。你想想看,消息从生产者发出来,到消费者收到,中间经历了什么?
- Queue(队列):消息的“收件箱”。消息最终都存在这里,等着消费者来取。
- Exchange(交换机):消息的“路由器”。生产者不直接把消息扔进队列,而是扔给 Exchange。Exchange 根据规则,决定把消息投递到哪个或哪些队列。
- Binding(绑定):连接 Exchange 和 Queue 的“规则线”。它告诉 Exchange:“嘿,如果消息符合这个条件,就把它送到这个队列去。”
我在项目中遇到过不少新手,上来就以为生产者直接发消息到队列。其实不是的。RabbitMQ 的设计哲学是:生产者只跟 Exchange 打交道,消费者只跟 Queue 打交道。这个解耦非常巧妙。
4.1.1 Queue(队列)
队列就是消息的容器。它有几个关键属性:
- 名称:每个队列有个唯一名字。不指定的话,RabbitMQ 会自动生成一个。
- 持久化:如果设为
durable=true,RabbitMQ 重启后队列还在。我建议生产环境一律开持久化,别省这点性能。 - 排他性:
exclusive=true表示这个队列只被当前连接使用,连接断开就自动删除。临时队列常用这个。 - 自动删除:
auto-delete=true表示最后一个消费者断开后,队列自动删除。
避坑指南:我曾经在测试环境忘了关自动删除,结果调试到一半,消费者一断开,队列没了,消息全丢了。排查了半天才发现是 auto-delete 搞的鬼。所以,生产环境务必明确设置这些参数。
4.1.2 Exchange(交换机)
Exchange 是 RabbitMQ 的大脑。它收到消息后,根据类型和绑定规则,决定消息的去向。常见的 Exchange 类型有四种:
| 类型 | 路由规则 | 典型场景 |
|---|---|---|
| Direct | 消息的 routing key 与队列绑定的 routing key 完全匹配 | 点对点通信,比如玩家私聊 |
| Topic | routing key 支持通配符匹配(* 匹配一个词,# 匹配零个或多个词) |
按主题分发,比如服务器日志分类 |
| Fanout | 忽略 routing key,把消息广播到所有绑定的队列 | 广播通知,比如全服公告 |
| Headers | 根据消息的 header 属性匹配,而不是 routing key | 复杂路由条件,用得较少 |
我个人习惯,游戏服务器里最常用的是 Direct 和 Topic。Fanout 偶尔用在跨服广播上。Headers 嘛,说实话,我做了这么多年游戏,几乎没用过。
4.1.3 Binding(绑定)
Binding 就是一条规则。它把 Exchange 和 Queue 连起来,并指定一个 routing key。举个例子:
# 创建一个名为 "player_queue" 的队列
# 绑定到 "game_exchange" 交换机,routing key 为 "player.login"
channel.queueBind("player_queue", "game_exchange", "player.login");
这条绑定意味着:当消息发到 game_exchange,并且 routing key 是 player.login 时,这条消息就会被投递到 player_queue。
小技巧:一个队列可以绑定多个 routing key,也可以绑定到多个 Exchange。反过来,一个 Exchange 也可以绑定多个队列。这种多对多的关系,让消息路由变得非常灵活。
4.2 安装与配置
理论说完了,咱们动手装一个。我以 CentOS 7 为例,Windows 和 Mac 的安装方式大同小异,官网都有文档。
4.2.1 安装 Erlang
RabbitMQ 是用 Erlang 写的,所以得先装 Erlang。注意版本匹配,别装错了。我建议直接用 RabbitMQ 官方提供的 Erlang 包。
# 添加 Erlang 仓库
wget https://packages.erlang-solutions.com/erlang-solutions-2.0-1.noarch.rpm
rpm -Uvh erlang-solutions-2.0-1.noarch.rpm
# 安装 Erlang
yum install -y erlang
# 验证安装
erl -version
嗯,这里要注意:Erlang 版本和 RabbitMQ 版本有对应关系。装之前去 RabbitMQ 官网查一下兼容性列表,省得后面出幺蛾子。
4.2.2 安装 RabbitMQ
# 下载 RabbitMQ 的 RPM 包
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.12.0/rabbitmq-server-3.12.0-1.el7.noarch.rpm
# 安装
rpm -ivh rabbitmq-server-3.12.0-1.el7.noarch.rpm
# 启动服务
systemctl start rabbitmq-server
# 设置开机自启
systemctl enable rabbitmq-server
# 查看状态
systemctl status rabbitmq-server
警告:安装过程中如果报依赖缺失,比如 socat,直接用 yum install -y socat 装上就行。我曾经在一台最小化安装的服务器上踩过这个坑,折腾了半小时。
4.2.3 启用管理插件
RabbitMQ 自带一个 Web 管理界面,非常方便。我个人习惯一装好就把它打开。
# 启用管理插件
rabbitmq-plugins enable rabbitmq_management
# 重启服务
systemctl restart rabbitmq-server
然后打开浏览器,访问 http://你的服务器IP:15672。默认用户名密码都是 guest。不过注意,guest 用户只能在 localhost 登录。远程访问的话,得新建一个用户。
4.2.4 创建用户与虚拟主机
生产环境里,我建议为每个项目或每个服务创建独立的用户和虚拟主机(vhost)。vhost 相当于 RabbitMQ 里的命名空间,不同 vhost 之间的 Exchange、Queue 完全隔离。
# 创建用户
rabbitmqctl add_user game_user game_password
# 设置用户标签(管理员权限)
rabbitmqctl set_user_tags game_user administrator
# 创建虚拟主机
rabbitmqctl add_vhost game_vhost
# 授权用户访问虚拟主机
rabbitmqctl set_permissions -p game_vhost game_user ".*" ".*" ".*"
这三条 ".*" 分别代表:配置权限、写权限、读权限。生产环境可以按需收紧,比如只给某个用户读某个队列的权限。
避坑指南:我曾经在项目初期图省事,所有服务共用一个 vhost 和一个 guest 用户。结果后来微服务一多,队列和交换机乱成一锅粥,排查问题非常痛苦。所以,从一开始就做好隔离,后面会省心很多。
4.3 验证安装
装完了,咱们写个简单的 Java 代码验证一下。这里用 RabbitMQ 的 Java 客户端。
// 生产者:发送一条消息
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("game_user");
factory.setPassword("game_password");
factory.setVirtualHost("game_vhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// 声明一个队列
channel.queueDeclare("hello_queue", true, false, false, null);
// 发送消息
String message = "Hello RabbitMQ!";
channel.basicPublish("", "hello_queue", null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
}
// 消费者:接收消息
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("game_user");
factory.setPassword("game_password");
factory.setVirtualHost("game_vhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare("hello_queue", true, false, false, null);
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
channel.basicConsume("hello_queue", true, deliverCallback, consumerTag -> {});
System.out.println(" [*] Waiting for messages...");
// 让程序保持运行
Thread.sleep(10000);
}
先跑生产者,再跑消费者。如果控制台打印出消息,说明 RabbitMQ 安装配置成功了。
小提示:代码里 queueDeclare 的第二个参数 true 表示队列持久化。生产环境一定要开。第三个参数 false 表示非排他,第四个 false 表示不自动删除。这四个参数,我建议你记牢,面试也常问。
4.4 本章小结
这一章,咱们把 RabbitMQ 的三大核心概念讲透了。Exchange 负责路由,Queue 负责存储,Binding 负责连接。安装配置也走了一遍,从 Erlang 到 RabbitMQ,再到管理插件和用户权限。
下一章,我会带你深入 Exchange 的四种类型,用实际代码演示它们的工作方式。到时候你会发现,理解了 Exchange,RabbitMQ 就算入门了。
好,先到这里。动手装一个试试,有问题咱们下章聊。