1. 装个消息队列而已,为什么值得单独写一篇
如果你搜到这篇,八成是已经在Linux服务器上准备部署RabbitMQ了。先说句实话:单纯把RabbitMQ跑起来,比很多人想象中要简单,真正卡住人的,往往是它前后那些不起眼的小事——Erlang版本对不对、主机名能不能解析、端口有没有被防火墙拦、内存阈值够不够。Linux安装RabbitMQ这件事,步骤本身不复杂,但环境差异带来的坑相当多,值得从头到尾认真捋一遍。
RabbitMQ本质上是一个基于Erlang/OTP开发的消息中间件,它默认支持AMQP 0-9-1协议,还可以通过插件支持MQTT、STOMP等协议。最常见的用法是解耦生产者和消费者:生产者只管把消息扔进队列,消费者按自己的节奏去处理。这种架构在微服务之间做异步调用、削峰填谷、任务分发时非常实用。我身边不少同事第一次接触它,都是在项目里接到类似"订单创建后要通知库存服务、积分服务、日志服务"这种需求,如果同步调用,下游一慢整个接口都跟着慢,改成RabbitMQ之后压力立刻小了很多。
安装RabbitMQ有一个隐形的先决条件:它依赖Erlang运行时。也就是说,装RabbitMQ之前你必须先保证系统里有一份匹配版本的Erlang。这个依赖关系是后面所有问题的根源,很多启动失败、节点连不上、客户端报错,最后追根溯源都是在这里栽的跟头。
这篇博文会把Linux安装RabbitMQ的完整链路走一遍,包括安装前的版本规划、用官方源安装、用通用二进制包在离线环境装、安装后的用户权限和插件配置、从生产环境角度做的几项小调整,以及一套可以直接照抄的排查流程。不管你是第一次接触消息队列的开发者,还是被叫去救火的运维,都能找到能直接用的内容。
2. 动手前先定三个变量:发行版、Erlang版本、主机名
2.1 发行版差异决定了安装方式
同样是Linux,发行版不同,安装路径完全不同。我用表格把常见情况列一下,方便你对照自己的环境:
| 发行版 | 包管理器 | 推荐的安装方式 |
|---|---|---|
| Ubuntu / Debian | apt | 添加RabbitMQ官方apt仓库 |
| CentOS / RHEL / Rocky Linux | dnf / yum | 添加RabbitMQ官方RPM仓库 |
| 任意Linux、无外网环境 | 手动解压 | 使用官方通用Unix二进制包 |
这篇文章以apt仓库安装为主,因为Ubuntu和Debian是使用量最大的两类系统,也是不少云服务器默认的系统。同时我会单独写一节二进制包安装,照顾内网环境和那些"系统太老、不想给服务器引入额外软件源"的场景。
动手之前先用一条命令确认系统版本,后面配置仓库时要用到版本代号,比如Ubuntu 22.04对应的代号是jammy,Debian 12对应的代号是bookworm:
cat /etc/os-release2.2 Erlang和RabbitMQ的版本兼容关系
这是整篇文章最值得记住的一个点:RabbitMQ对Erlang版本有严格的兼容范围,不是随便装一个Erlang就能跑的。装高了可能启动直接崩,装低了同样起不来,或者运行一段时间后出现莫名奇妙的连接错误。
我根据官方版本兼容表整理了一个粗略对应关系,实际安装时一定要以RabbitMQ官方文档页面的版本兼容表为准:
| RabbitMQ版本 | 适配的Erlang版本 |
|---|---|
| 3.13.x | 26.2及以上 |
| 3.12.x | 25.3、26.x |
| 3.11.x | 23.2到26.x |
| 3.10.x | 23.2到25.x |
注意这只是大致范围,不同的小版本还会有细微差别。我见过最典型的翻车现场就是有人在网上随便找了一篇老教程,把最新版的Erlang装上去,结果RabbitMQ 3.10系列根本不认,启动日志里直接报Erlang版本过高。
因此在正式安装之前,建议你先确定要装哪个RabbitMQ版本,再反推对应的Erlang版本。如果完全没有版本偏好,那就用官方仓库里配套的rabbitmq-server,同时把官方仓库里的rabbitmq-erlang也装上,这样版本匹配由仓库维护者保证,省掉很多麻烦。
2.3 主机名解析:看起来没关系,实际影响非常大
RabbitMQ节点启动后,节点名称默认是rabbit@主机名,Erlang在运行时会反复做主机名解析。如果/etc/hostname里的名字和/etc/hosts里配置不一致,节点可能起不来,或者起来之后集群节点互相找不到。
安装前先执行这几条命令检查:
hostname cat /etc/hostname cat /etc/hosts hostname -fhostname -f返回的完整域名,如果没有私有DNS,直接返回主机名也是正常的。这里有两个常见的坑:一个是主机名里不能有下划线,比如my_server这种名字,Erlang处理起来会有兼容问题,最好改成my-server;另一个是/etc/hosts里必须有一条把本机主机名映射到127.0.1.1或内网IP的记录。
我遇到过一次很尴尬的情况:服务器启动RabbitMQ一直报nodedown,怎么看都没有头绪,后来发现是系统管理员把主机名改成了带下划线的格式,Erlang解析节点名失败,服务实际没有正常注册到epmd。所以不要跳过这一步,几分钟的检查能省掉后面几小时的排障时间。
3. 官方源安装:适合多数联网服务器的稳妥方案
3.1 添加官方仓库和签名密钥
在Ubuntu和Debian上,我推荐用RabbitMQ官方仓库而不是系统自带的源。官方源的好处是版本更新及时,Erlang包也由官方仓库同步维护,能最大程度避免版本不匹配的问题。
首先安装几个基础工具:
sudo apt-get update sudo apt-get install -y curl gnupg apt-transport-https接着需要导入官方仓库的GPG密钥。不同版本的官方文档提供的导入命令会略有差异,核心动作是把公钥下载下来,做成keyring文件放到/usr/share/keyrings/下。现在的Debian系系统都推荐用signed-by的方式引用keyring,而不是老教程里的apt-key add,因为apt-key是全局信任,一旦泄露等于信任了所有用该密钥签名的源,而keyring方式只对指定的源生效,安全性高很多。
导入密钥后,在/etc/apt/sources.list.d/下新建一个源文件,内容格式类似:
deb [signed-by=/usr/share/keyrings/rabbitmq.gpg] https://官方仓库地址/rabbitmq-server/deb/系统代号 main deb [signed-by=/usr/share/keyrings/rabbitmq.gpg] https://官方仓库地址/rabbitmq-erlang/deb/系统代号 main这里我不建议手动背链接,直接去RabbitMQ官方安装文档页面,复制你系统对应的配置段落最可靠。很多人在这一步复制错仓库,导致后面apt update报404,或者装出来的包版本不对。
3.2 安装、启动和基本自检
源配置好之后更新一次索引,然后直接安装:
sudo apt-get update sudo apt-get install -y rabbitmq-server安装完成后,设置开机自启并马上启动:
sudo systemctl enable rabbitmq-server sudo systemctl start rabbitmq-server刚装完不要急着配用户,先确认服务真的起来了,用status查看服务状态,再用rabbitmqctl status看节点信息:
sudo systemctl status rabbitmq-server --no-pager sudo rabbitmqctl statusrabbitmqctl status的输出里能看到RabbitMQ版本号、Erlang版本号、节点名称、内存使用情况等信息。我每次装完都会看一眼这里的版本号,确认和官方兼容表对应,防止装到不匹配的Erlang。
3.3 为什么我不建议从系统自带源直接装
系统自带的apt源里也有rabbitmq-server,但版本通常比较保守,有的发行版甚至落后主版本两三个大版本。如果你只是本地测试,装系统源里的无所谓;但生产环境建议用官方源。
另外,系统源里一般不会单独提供配套的Erlang包,你还需要自己装Erlang,版本不一定匹配。官方源把rabbitmq-erlang和rabbitmq-server打包在一起维护,版本联动,这是我最推荐官方源的原因。本质上就是用一点点配置成本,换掉未来不可预期的一堆排障成本。
4. 通用二进制包安装:离线环境与特殊系统的选择
4.1 前置依赖:Erlang怎么解决
如果你在内网环境、或者服务器系统太老无法使用官方源,通用Unix二进制包是最实用的方案。RabbitMQ官方提供编译好的rabbitmq-server-generic-unix包,解压就能用,但这个包里不包含Erlang运行时,所以Erlang需要单独装。
Erlang的获取有几个途径:一是用RabbitMQ官方提供的Erlang安装包,这个最稳妥;二是用Erlang Solutions提供的安装包;三是直接源码编译。源码编译耗时较长,而且容易出编译依赖问题,除非系统实在特殊,否则我不建议在安装RabbitMQ这个环节顺便折腾编译。
判断Erlang是否可用的最快方式:
erl -version能正常输出版本号,说明Erlang运行时可用,接下来就是选一个和RabbitMQ版本匹配的Erlang版本。
4.2 解压、配置、启动二进制包
从RabbitMQ官方Release页面下载对应版本的通用Unix包,上传到服务器后执行:
sudo mkdir -p /opt/rabbitmq sudo tar -xJf rabbitmq-server-generic-unix-版本号.tar.xz -C /opt/rabbitmq --strip-components=1解压到/opt/rabbitmq目录下之后,可以把/opt/rabbitmq/sbin加入PATH,方便后面执行命令:
export PATH=/opt/rabbitmq/sbin:$PATH如果你只想临时生效,直接在当前shell导出即可;想长期生效,就写进/etc/profile.d/rabbitmq.sh。
启动服务用:
sudo /opt/rabbitmq/sbin/rabbitmq-server -detached-detached参数表示以后台模式运行,类似daemon。启动后用sbin/rabbitmqctl status检查节点状态。停止服务的命令是:
sudo /opt/rabbitmq/sbin/rabbitmqctl stop这里要特别提醒一个通用包特有的坑:通用包默认的运行用户是当前用户,数据目录默认在当前用户的家目录下。如果你用root解压并启动,RabbitMQ会把数据写到/root/.rabbitmq目录下,这很不规范,也不方便后期维护。正确做法是先建一个专门的系统用户:
sudo useradd -r -s /usr/sbin/nologin rabbitmq sudo chown -R rabbitmq:rabbitmq /opt/rabbitmq然后用su -s /bin/sh - rabbitmq -c '/opt/rabbitmq/sbin/rabbitmq-server -detached'启动,让节点以rabbitmq用户运行。我最初用通用包时就因为偷懒用root启动,后面做集群时权限问题折腾很久,所以这一步别省。
4.3 systemd托管方式
手动用-detached启动没问题,但如果服务器重启,服务不会自动起来。生产环境我建议把RabbitMQ托管给systemd。在/etc/systemd/system/rabbitmq.service下写一个简单的unit文件:
[Unit] Description=RabbitMQ Server After=network.target [Service] User=rabbitmq Group=rabbitmq WorkingDirectory=/opt/rabbitmq ExecStart=/opt/rabbitmq/sbin/rabbitmq-server ExecStop=/opt/rabbitmq/sbin/rabbitmqctl stop Restart=on-failure [Install] WantedBy=multi-user.target然后重新加载systemd配置:
sudo systemctl daemon-reload sudo systemctl enable rabbitmq sudo systemctl start rabbitmq这样RabbitMQ就纳入了systemd管理,和apt方式安装的服务相比,差别只在启动脚本路径,其余配置方式完全一致。
5. 装完不等于能用:用户、权限、插件和防火墙
5.1 创建管理员账号并分配权限
刚安装完成的RabbitMQ默认有一个guest账号,密码也是guest。但guest账号被限制只能从本机连接,如果你从另一台服务器连RabbitMQ,会直接报权限拒绝。所以装完RabbitMQ第一件事永远是:创建一个自己的管理员账号。
sudo rabbitmqctl add_user admin 强密码 sudo rabbitmqctl set_user_tags admin administrator sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"三条命令分别做三件事:创建用户、把用户标记为管理员、给用户在默认虚拟主机/下配置全部权限。set_permissions后面的三个.*分别表示配置、写、读的权限正则,直接给全部权限是开发环境最省事的做法,生产环境需要收紧。
需要注意,命令行里直接写密码会留在shell历史中,正式环境建议用rabbitmqctl add_user时通过交互式输入,或者后续从配置文件读取。这是容易忽略的安全细节。
5.2 启用管理插件和Web控制台
RabbitMQ自带一个Web管理界面插件,但默认没有开启。启用只需要一条命令:
sudo rabbitmq-plugins enable rabbitmq_management启用成功后,Web管理控制台会监听15672端口。在浏览器里访问http://服务器IP:15672,用刚才创建的admin账号登录,就能看到队列、连接、交换机、虚拟机等一系列信息。这个控制台对排查消息堆积问题特别有用,比一个个敲命令直观得多。
如果你不打算开放Web管理界面,也可以只保留5672端口给业务客户端使用,15672端口不开放。但开发环境建议开起来,调试效率会高很多。
这个时候还要注意防火墙。很多云服务器默认防火墙规则比较严,需要在安全组里放行端口:
| 端口 | 默认用途 | 说明 |
|---|---|---|
| 4369 | epmd | Erlang节点映射,集群和分布式节点通信需要 |
| 5672 | AMQP | 客户端连接的主端口 |
| 15672 | Web管理界面 | HTTP API和控制台 |
| 25672 | 集群通信 | 节点间通信,单机部署用不到 |
如果你用的是ufw,放行命令是:
sudo ufw allow 5672/tcp sudo ufw allow 15672/tcp如果是firewalld,则是:
sudo firewall-cmd --permanent --add-port=5672/tcp sudo firewall-cmd --permanent --add-port=15672/tcp sudo firewall-cmd --reload5.3 从客户端进行第一次真实收发
不要只停留在Web界面看状态,我建议装完立刻做一次真实的收发验证。先用nc确认端口通不通:
nc -vz 服务器IP 5672再用一段简单的Python脚本做真实消息收发。安装pika库:
pip install pika写一个发送消息的脚本:
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( host='服务器IP', port=5672, credentials=pika.PlainCredentials('admin', '强密码') )) channel = connection.channel() channel.queue_declare(queue='test_queue') channel.basic_publish(exchange='', routing_key='test_queue', body='hello rabbitmq') print('消息已发送') connection.close()再写一个接收消息的脚本:
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( host='服务器IP', port=5672, credentials=pika.PlainCredentials('admin', '强密码') )) channel = connection.channel() channel.queue_declare(queue='test_queue') def callback(ch, method, properties, body): print('收到消息:', body) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume(queue='test_queue', on_message_callback=callback, auto_ack=False) print('等待消息中...') channel.start_consuming()先运行发送脚本,再运行接收脚本,能看到消息被正常接收,就说明整个安装链路是通的。这一步做完,才算真正的“装好了”。
6. 启动失败与连不上:一套可以照抄的排查链路
6.1 服务起不来时先看这三样
即使前面步骤都做对了,也还是有环境差异可能导致启动失败。我的排查顺序固定是:日志、Erlang版本、主机名。
RabbitMQ的启动日志在/var/log/rabbitmq/目录下(二进制包安装在/opt/rabbitmq/log下),主要的日志文件是rabbit@主机名.log和rabbit@主机名-sasl.log。起不来先看这两个日志,比在网上到处搜索报错有效率得多。
Erlang版本问题通常会在日志里留下类似"Erlang version mismatch"或"unsupported"的关键词。处理方式很直接:卸载当前的Erlang,换成版本兼容表里对应的版本。
主机名问题前面已经提过,典型表现是日志里出现hostname xxx is not valid,或者Unable to connect to epmd。处理方式是修改/etc/hosts,确保本机主机名能正确解析。
6.2 远程拿不到连接的另一半原因
如果服务在服务器本机一切正常,rabbitmqctl status能返回信息,但从其他机器连不上,问题大概率出在监听地址和防火墙。
用这条命令看RabbitMQ实际监听在哪个地址:
ss -lntp | grep 5672如果看到监听地址是127.0.0.1:5672,说明RabbitMQ只监听本机回环地址,外部自然连不上。解决方法是编辑/etc/rabbitmq/rabbitmq.conf,设置监听所有接口:
listeners.tcp.default = 5672默认配置下RabbitMQ本来就监听0.0.0.0,但有些环境下因为配置文件问题会变成只监听本机。改完之后重启RabbitMQ:
sudo systemctl restart rabbitmq-server还有一种很隐蔽的情况:云服务器的安全组里加了规则,但服务器本地的ufw或iptables没放行。两者都要检查,只改一个没用。
6.3 内存被打爆:小机器的头号杀手
RabbitMQ默认的内存阈值是物理内存的40%,也就是系统内存最多可以被RabbitMQ用到40%。这个默认值在大内存机器上没毛病,但在只有2G内存的云服务器上,40%也就是800M。如果同一台机器上还跑着数据库、Web服务,RabbitMQ启动时内存涨得太快,系统很容易进入OOM状态,表现是进程被系统杀掉,rabbitmqctl status直接报nodedown。
我遇到过一次很典型的情况:一台1G内存的机器上装了RabbitMQ,启动后不到一分钟进程消失。查dmesg发现是内核OOM把beam进程杀了。当时还以为是安装有问题,试了好几遍都没用,后来才反应过来是内存阈值问题。
处理方式是调整/etc/rabbitmq/rabbitmq.conf里的内存高水位:
vm_memory_high_watermark = 0.3低内存机器建议调整到0.25到0.3之间,保守一点总比被OOM杀掉好。改完配置后重启服务,再看进程存活时间。如果内存实在太小,那就只能考虑换大一点的机器,或者把RabbitMQ单独部署。
7. 上线前值得做的小调整:内存阈值、磁盘检查与日志
7.1 内存高水位与磁盘空间余量
前面已经讲到内存阈值,这里补充一个关键认知:内存高水位不是“到阈值才限制”,而是“超过阈值后RabbitMQ会主动阻塞所有生产者的连接”,防止继续接收消息导致内存失守。配置设太高,消息大量堆积时会先拖垮系统;设太低,又可能过早阻塞生产者。生产环境我不建议直接用默认值,而是根据节点内存和预期消息量做一次估算。
假设你有16G内存,RabbitMQ独占一台机器,那么0.4默认值还算合理;如果是2G内存的共享机器,建议按0.25设置。这个值随时可以改,不需要重装,改完配置文件后重启即可生效。
磁盘空间的设置也值得检查。RabbitMQ默认在磁盘空闲空间低于某个阈值时会停止接收新消息,这个默认阈值通常是50M或基于内存计算的一个相对值。生产环境建议显式设置为一个具体值:
disk_free_limit = 2GB更严谨的做法是设置相对值,比如保留总磁盘的10%:
disk_free_limit.relative = 0.1磁盘满导致消息积压的故障我见过不止一次,基本都是因为没看这个参数,只盯着内存去了。
7.2 日志方位、轮转与诊断工具
RabbitMQ运行一段时间后,日志文件会越来越大。默认情况下日志在/var/log/rabbitmq/目录下,你可以用logrotate做日志轮转,也可以直接在RabbitMQ配置里限制日志文件大小。
RabbitMQ本身支持日志文件拆分,在配置文件里设置:
log.file.size = 10485760 log.file.count = 5这表示单个日志文件达到10M就轮转,最多保留5个历史文件。对于多数业务量不大的场景,这个配置完全够用。
遇到问题不要一上来就重启服务,建议先用诊断命令收集关键信息:
sudo rabbitmq-diagnostics -q ping sudo rabbitmq-diagnostics check_running sudo rabbitmq-diagnostics check_port_connectivity sudo rabbitmq-diagnostics check_local_alarms这些命令分别检查节点存活、运行状态、端口连接、告警信息。我最常用的是check_local_alarms,它能直接列出当前有哪些告警在起作用,比如内存告警、磁盘告警。如果服务莫名不接受消息,先跑一遍这个命令,多半能找到原因。
7.3 版本升级时别踩的更新坑
最后提一下升级。很多人在安装阶段顺利跑通后,过几个月想升级RabbitMQ版本,于是直接下载新包覆盖。这里有个很容易踩的坑:RabbitMQ升级不能简单粗暴地停服务、换文件、再启动,一些跨大版本升级需要先迁移数据目录。
安全升级流程大致是:先导出配置和定义(Web管理界面的“Export definitions”),然后停止RabbitMQ节点,备份数据目录,再安装新版本,最后启动并校验。更稳妥的做法是在测试环境先做一次同样的升级演练,确认没有问题再动生产。
我个人的习惯是:升级前一定记录当前版本号、Erlang版本号、已启用的插件列表。这三者任何一个对不上,都可能导致升级后服务异常。
8. 最后说几句心里话
这几轮安装和排障下来,最大的感受是:Linux安装RabbitMQ这件事,真正的难点从来不在“安装”本身,而在安装之前和安装之后。安装之前要选对Erlang版本、确认主机名、规划好端口;安装之后要配置用户权限、关注内存阈值、了解日志和诊断工具。算下来的工作量,比执行几条安装命令多得多,但这些细节才决定你在生产环境能不能睡得踏实。
还有一个很实用的习惯分享给大家:无论用哪种方式安装,装完后都建议把rabbitmqctl status、rabbitmq-plugins list、rabbitmq-diagnostics这几个命令的输出保存一份。排查问题时对照“安装当时的正常状态”和“当下的异常状态”,定位起来会快很多。
如果你看完这篇已经成功跑通了基础环境,下一步可以考虑的事情是集群部署和高可用方案。单节点RabbitMQ在开发环境完全够用,但生产环境至少要规划镜像队列和集群节点。等到真正要做这部分时,你会发现这篇文章里反复强调的主机名、端口、Erlang版本,全部会在集群场景再次出现,而且每一个都是硬门槛。提前把这些基础打牢,后面会省心得多。