Java 中间件之 RabbitMQ 快速入门: RabbitMQ 介绍与安装部署

概述

RabbitMQ 用 Erlang 写的,手动安装要先把 Erlang 运行时和它的版本对应关系搞对------这是新手踩的第一个坑。

本文用 Docker 一条命令把单机版跑起来,理清 5672 / 15672 两个端口分别干什么,并给出一套可复制的"安装是否真的成功"验证流程。

纲要

  • 关键概念
    • RabbitMQ:基于 Erlang 开发、实现 AMQP 协议的开源消息中间件
    • 五种角色:publisher、consumer、exchange、queue、virtualHost
    • 两个端口:5672 (AMQP 消息通信)、15672(Management 管理控制台 UI)
    • 三种装法:Docker 单机部署 (推荐)、Linux 原生安装 、集群部署
  • 核心流程
    • 拉取镜像 → docker run 启动容器 → 访问控制台 → 用默认账号登录 → 看节点/交换机/队列
    • 建立 Connection → 创建 Channel → 声明队列 → 收发消息
  • 涉及命令与配置
    • docker pull rabbitmq:3.8-management / docker load -i mq.tar
    • docker run 完整参数:-e、-v、--name、--hostname、-p、-d
    • 验证:docker ps、docker logs、ss -tlnp、curl 调 HTTP API、rabbitmqctl status
    • 排障:端口占用、容器退出、控制台打不开、guest 账号无法远程登录

RabbitMQ 是什么

RabbitMQ 是一个开源的消息中间件(Message Queue,事件驱动架构里的 Broker),由 Erlang 语言 开发,实现了 AMQP(Advanced Message Queuing Protocol)协议,同时也支持 STOMP、MQTT 等协议通过插件扩展。

Erlang 是爱立信为电信交换机设计的语言,天生面向并发、面向分布式:轻量进程、Actor 模型、软实时、热更新。RabbitMQ 建在它上面,也就天然带了这些特征------单机吞吐不是它的强项,但消息可靠性和稳定性是。官方文档里给的单机吞吐参考是万级/秒量级,做业务异步解耦、削峰填谷绰绰有余;真要做到百万级吞吐,那是 Kafka / RocketMQ 的战场。

选型时常见的四种 MQ 对比:

RabbitMQ ActiveMQ RocketMQ Kafka
公司/社区 Rabbit(原 Pivotal) Apache 阿里 Apache
开发语言 Erlang Java Java Scala & Java
协议支持 AMQP、XMPP、SMTP、STOMP OpenWire、STOMP、REST、XMPP、AMQP 自定义协议 自定义协议
可用性 高 一般 高 高
单机吞吐量 一般 差 高 非常高
消息延迟 微秒级 毫秒级 毫秒级 毫秒以内
消息可靠性 高 一般 高 一般

一句话记法:追求可靠性选 RabbitMQ / RocketMQ,追求吞吐选 Kafka / RocketMQ,追求低延迟选 RabbitMQ / Kafka。

整体结构与核心概念

这是理解后面所有操作的基础,先记住这张图:
#mermaid-svg-He4WGwRjlAzebbWm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-He4WGwRjlAzebbWm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-He4WGwRjlAzebbWm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-He4WGwRjlAzebbWm .error-icon{fill:#552222;}#mermaid-svg-He4WGwRjlAzebbWm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-He4WGwRjlAzebbWm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-He4WGwRjlAzebbWm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-He4WGwRjlAzebbWm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-He4WGwRjlAzebbWm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-He4WGwRjlAzebbWm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-He4WGwRjlAzebbWm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-He4WGwRjlAzebbWm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-He4WGwRjlAzebbWm .marker.cross{stroke:#333333;}#mermaid-svg-He4WGwRjlAzebbWm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-He4WGwRjlAzebbWm p{margin:0;}#mermaid-svg-He4WGwRjlAzebbWm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-He4WGwRjlAzebbWm .cluster-label text{fill:#333;}#mermaid-svg-He4WGwRjlAzebbWm .cluster-label span{color:#333;}#mermaid-svg-He4WGwRjlAzebbWm .cluster-label span p{background-color:transparent;}#mermaid-svg-He4WGwRjlAzebbWm .label text,#mermaid-svg-He4WGwRjlAzebbWm span{fill:#333;color:#333;}#mermaid-svg-He4WGwRjlAzebbWm .node rect,#mermaid-svg-He4WGwRjlAzebbWm .node circle,#mermaid-svg-He4WGwRjlAzebbWm .node ellipse,#mermaid-svg-He4WGwRjlAzebbWm .node polygon,#mermaid-svg-He4WGwRjlAzebbWm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-He4WGwRjlAzebbWm .rough-node .label text,#mermaid-svg-He4WGwRjlAzebbWm .node .label text,#mermaid-svg-He4WGwRjlAzebbWm .image-shape .label,#mermaid-svg-He4WGwRjlAzebbWm .icon-shape .label{text-anchor:middle;}#mermaid-svg-He4WGwRjlAzebbWm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-He4WGwRjlAzebbWm .rough-node .label,#mermaid-svg-He4WGwRjlAzebbWm .node .label,#mermaid-svg-He4WGwRjlAzebbWm .image-shape .label,#mermaid-svg-He4WGwRjlAzebbWm .icon-shape .label{text-align:center;}#mermaid-svg-He4WGwRjlAzebbWm .node.clickable{cursor:pointer;}#mermaid-svg-He4WGwRjlAzebbWm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-He4WGwRjlAzebbWm .arrowheadPath{fill:#333333;}#mermaid-svg-He4WGwRjlAzebbWm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-He4WGwRjlAzebbWm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-He4WGwRjlAzebbWm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-He4WGwRjlAzebbWm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-He4WGwRjlAzebbWm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-He4WGwRjlAzebbWm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-He4WGwRjlAzebbWm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-He4WGwRjlAzebbWm .cluster text{fill:#333;}#mermaid-svg-He4WGwRjlAzebbWm .cluster span{color:#333;}#mermaid-svg-He4WGwRjlAzebbWm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-He4WGwRjlAzebbWm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-He4WGwRjlAzebbWm rect.text{fill:none;stroke-width:0;}#mermaid-svg-He4WGwRjlAzebbWm .icon-shape,#mermaid-svg-He4WGwRjlAzebbWm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-He4WGwRjlAzebbWm .icon-shape p,#mermaid-svg-He4WGwRjlAzebbWm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-He4WGwRjlAzebbWm .icon-shape .label rect,#mermaid-svg-He4WGwRjlAzebbWm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-He4WGwRjlAzebbWm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-He4WGwRjlAzebbWm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-He4WGwRjlAzebbWm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 隔离
virtualHost: /itcast
发布消息
路由 RoutingKey
推送消息
publisher 生产者
exchange 交换机
queue 队列
consumer 消费者
virtualHost: /
发布消息
路由 RoutingKey
推送消息
publisher 生产者
exchange 交换机
queue 队列
consumer 消费者

两个虚拟主机里的交换机可以同名、队列可以同名,互不干扰。这就是多租户隔离。

角色职责:

角色 作用 典型误用
publisher 消息生产者,把消息发给 exchange 以为消息是直接发给 queue 的
consumer 消息消费者,从 queue 取消息处理 一个队列挂多个消费者时以为是"每个都收一份",实际是竞争消费
exchange 交换机,消息的路由器,按类型和 RoutingKey 投递到队列 忘记绑队列,消息发出去直接被丢弃(RabbitMQ 不报错)
queue 队列,缓存消息,是真正存消息的地方 生产消费者两边声明的队列参数不一致,启动报 PRECONDITION_FAILED
virtualHost 虚拟主机,对 exchange/queue/消息做逻辑分组与隔离 所有业务共用一个 /,多项目互相踩
channel 操作 MQ 的句柄,收发消息都要通过它 把 Connection 当操作对象用;或者一个线程共用一个非线程安全的 Channel
connection TCP 长连接 每条消息新建一次连接,把 MQ 连接打满

一次完整的通信过程:
consumer queue Broker(RabbitMQ) publisher consumer queue Broker(RabbitMQ) publisher #mermaid-svg-CZoLYIyQetC8CdkS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CZoLYIyQetC8CdkS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CZoLYIyQetC8CdkS .error-icon{fill:#552222;}#mermaid-svg-CZoLYIyQetC8CdkS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CZoLYIyQetC8CdkS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CZoLYIyQetC8CdkS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CZoLYIyQetC8CdkS .marker.cross{stroke:#333333;}#mermaid-svg-CZoLYIyQetC8CdkS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CZoLYIyQetC8CdkS p{margin:0;}#mermaid-svg-CZoLYIyQetC8CdkS .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CZoLYIyQetC8CdkS text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-CZoLYIyQetC8CdkS .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CZoLYIyQetC8CdkS .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-CZoLYIyQetC8CdkS .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-CZoLYIyQetC8CdkS .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-CZoLYIyQetC8CdkS #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-CZoLYIyQetC8CdkS .sequenceNumber{fill:white;}#mermaid-svg-CZoLYIyQetC8CdkS #sequencenumber{fill:#333;}#mermaid-svg-CZoLYIyQetC8CdkS #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-CZoLYIyQetC8CdkS .messageText{fill:#333;stroke:none;}#mermaid-svg-CZoLYIyQetC8CdkS .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CZoLYIyQetC8CdkS .labelText,#mermaid-svg-CZoLYIyQetC8CdkS .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-CZoLYIyQetC8CdkS .loopText,#mermaid-svg-CZoLYIyQetC8CdkS .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-CZoLYIyQetC8CdkS .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-CZoLYIyQetC8CdkS .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-CZoLYIyQetC8CdkS .noteText,#mermaid-svg-CZoLYIyQetC8CdkS .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-CZoLYIyQetC8CdkS .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CZoLYIyQetC8CdkS .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CZoLYIyQetC8CdkS .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-CZoLYIyQetC8CdkS .actorPopupMenu{position:absolute;}#mermaid-svg-CZoLYIyQetC8CdkS .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-CZoLYIyQetC8CdkS .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-CZoLYIyQetC8CdkS .actor-man circle,#mermaid-svg-CZoLYIyQetC8CdkS line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-CZoLYIyQetC8CdkS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 建立 TCP Connection(5672) 在 Connection 上创建 Channel 声明 exchange / queue 并绑定 basicPublish 发送消息 exchange 按 RoutingKey 路由入队 建立 Connection + Channel basicConsume 订阅队列 推送消息 ack 确认 删除已确认的消息

注意 channel 这一层:Connection 是昂贵的 TCP 长连接,Channel 是复用在它上面的轻量逻辑连接。生产环境里一个应用通常只维持少量 Connection,每个线程各自开 Channel------Channel 不是线程安全的,别多线程共享同一个。

为什么用 Docker 装

原生安装 RabbitMQ 的麻烦在于 Erlang 版本强绑定:RabbitMQ 3.8 要求 Erlang 21.3 -- 23.x,3.9 要求 23.2 -- 24.x,装错版本服务直接起不来,报的错还是一句看不懂的 Erlang 栈。Docker 镜像把 Erlang 运行时、RabbitMQ 服务端、management 插件一起打包好了,一条命令解决。

课程环境是 CentOS7 虚拟机,下面的命令都在上面跑过。

Docker 单机部署

获取镜像

两种方式,二选一。有网就在线拉取:

bash 复制代码
# 拉取带管理控制台的官方镜像(3.8 系列,management 版自带 Web UI)
docker pull rabbitmq:3.8-management

# 想要最新稳定版可以用 3-management 这个滚动标签
docker pull rabbitmq:3-management

# 确认镜像到位
docker images | grep rabbitmq

这里有个坑:镜像标签千万别写成 rabbitmq:3.8 或 rabbitmq:latest。这两个标签的镜像没有预装 management 插件 ,启动后 15672 端口打不开,控制台根本不存在。认准带 -management 后缀的。

离线环境就用镜像包导入:

bash 复制代码
# 把课前资料里的 mq.tar 上传到虚拟机,比如 /tmp 目录
# 进入目录后加载
cd /tmp
docker load -i mq.tar

# 导入成功后再看一眼
docker images

导入成功后能看到 rabbitmq 3-management 这样的镜像记录。

启动容器

bash 复制代码
docker run \
  -e RABBITMQ_DEFAULT_USER=itcast \
  -e RABBITMQ_DEFAULT_PASS=123321 \
  -v mq-plugins:/plugins \
  --name mq \
  --hostname mq \
  -p 15672:15672 \
  -p 5672:5672 \
  -d \
  rabbitmq:3.8-management

参数逐个说清楚,别当黑盒抄:

参数 值 作用与注意事项
-e RABBITMQ_DEFAULT_USER itcast 初始化管理员账号。只在首次初始化时生效,数据卷已存在时改这个再重启没用
-e RABBITMQ_DEFAULT_PASS 123321 上面账号的密码
-v mq-plugins:/plugins 数据卷挂载 插件目录持久化,装了插件重启容器不丢
--name mq 容器名 后续 docker logs mq、docker exec -it mq bash 都用它
--hostname mq 主机名 RabbitMQ 节点名默认取自主机名(rabbit@主机名)。单机不配也能跑,但做集群或保留数据时必须固定,否则容器重建后节点名变了,mnesia 数据对不上,会出现节点起不来或数据丢失
-p 15672:15672 管理控制台 Web UI 端口,浏览器访问它
-p 5672:5672 AMQP 消息通信端口,客户端收发消息走它
-d 后台运行 不加就前台挂着,Ctrl+C 容器就停了
镜像名 rabbitmq:3.8-management 必须与本地已有的镜像 tag 一致

如果还要用集群或命令行工具,建议把 25672(节点间通信与 CLI 端口)也映射出来;单机学习用不上,先不映射。

启动后的目录与端口关系:

text 复制代码
宿主机(CentOS7)
├── Docker
│   └── 容器 mq (hostname=mq, 节点名 rabbit@mq)
│       ├── /var/lib/rabbitmq/mnesia/rabbit@mq   # 消息与元数据落盘目录
│       └── /plugins                              # 挂载到数据卷 mq-plugins
└── 端口映射
    ├── 5672  -> 容器内 5672   (AMQP 0-9-1,生产者/消费者连接)
    └── 15672 -> 容器内 15672  (Management UI / HTTP API)

验证安装成功

别只靠浏览器能打开就下结论,按顺序走一遍这六步:

第一步,容器是否真的 Up

bash 复制代码
docker ps --filter name=mq --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

正常输出应该能看到 Up 和 0.0.0.0:5672->5672/tcp, 0.0.0.0:15672->15672/tcp。状态是 Exited (1) 就直接跳到排障章节看日志。

第二步,日志里有没有启动完成标志

bash 复制代码
docker logs -f mq

RabbitMQ 启动比较慢(Erlang 虚拟机 + 建库),通常十几秒到一分钟。看到这几行才算就绪:

text 复制代码
  ##  ##      RabbitMQ 3.8.x
  ######  ##
  ##########  Copyright (c) 2007-2020 VMware, Inc.

  Starting broker... completed with 3 plugins.

日志里出现 completed with N plugins 就是启动完成的信号。看到 ERROR: epmd error 或 unable to connect to node 说明节点名/主机名出了问题。

第三步,端口是否真的在监听

bash 复制代码
# 宿主机上确认两个端口已被 docker 监听
ss -tlnp | grep -E '5672|15672'

# 没有 ss 就用 netstat 或 lsof
netstat -tlnp | grep -E '5672|15672'
lsof -i:15672

# 从另一台机器探测连通性(换成你的虚拟机 IP)
nc -zv 192.168.150.101 5672
nc -zv 192.168.150.101 15672

第四步,不打开浏览器也能验证:调 HTTP API

bash 复制代码
# 用刚设置的账号调管理 API,返回一大坨 JSON 说明服务正常
curl -u itcast:123321 http://localhost:15672/api/overview

# 只看关键字段(需要 jq,没装就去掉 | jq 部分)
curl -s -u itcast:123321 http://localhost:15672/api/overview \
  | jq '{rabbitmq_version, management_version, node, erlang_version}'

期望输出类似:

json 复制代码
{
  "rabbitmq_version": "3.8.19",
  "management_version": "3.8.19",
  "node": "rabbit@mq",
  "erlang_version": "23.3.4.11"
}

node 字段是 rabbit@mq,正好对上 --hostname mq。

第五步,容器内执行 rabbitmqctl 自检

bash 复制代码
docker exec -it mq rabbitmqctl status

# 看监听的 AMQP 端口
docker exec -it mq rabbitmqctl status | grep -A 5 "Interfaces"

# 确认 management 插件已启用
docker exec -it mq rabbitmq-plugins list | grep management

rabbitmq-plugins list 里 rabbitmq_management 前面应该是 [E*](E 表示显式启用)。

第六步,浏览器登录控制台

访问 http://192.168.150.101:15672(IP 换成你自己的虚拟机地址),用 itcast / 123321 登录。能进到 Overview 页,安装这一步就彻底完成了。

如果想从代码层面确认 5672 真的能收发消息,用 amqp-client 跑个最小连接测试:

xml 复制代码
<!-- pom.xml 依赖 -->
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.14.2</version>
</dependency>
java 复制代码
package cn.itcast.mq.helloworld;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * 安装验证:连上 5672,声明队列,发一条消息再收一条,确认 AMQP 链路通畅。
 */
public class MqConnectionTest {

    private static final String QUEUE_NAME = "install.check.queue";

    public static void main(String[] args) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        // 宿主机 IP + AMQP 端口 5672,不是 15672
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 虚拟主机,默认是 "/"
        factory.setVirtualHost("/");

        // try-with-resources 自动关闭连接,避免每次运行都留下一条 Connection
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {

            // 声明队列:持久化=false,独占=false,自动删除=true
            channel.queueDeclare(QUEUE_NAME, false, false, true, null);
            channel.basicPublish("", QUEUE_NAME, null, "hello rabbitmq".getBytes("UTF-8"));
            System.out.println("消息已发送");

            // 拉一条消息,autoAck=true 表示拿到即确认
            var response = channel.basicGet(QUEUE_NAME, true);
            if (response != null) {
                System.out.println("收到消息: " + new String(response.getBody(), "UTF-8"));
            } else {
                System.out.println("队列为空,未收到消息");
            }
        }
    }
}

跑完控制台打印 收到消息: hello rabbitmq,说明 5672 通信正常。再去控制台 Queues 页能看到这个队列(因为设置了 auto-delete,连接断开后会自动消失)。

管理控制台初识

登录后的界面分六个 Tab,各自看什么:

Tab 看什么 现在应该看到的状态
Overview 节点信息、硬件资源、消息吞吐总览 单节点 rabbit@mq,没有集群
Connections 与 Broker 建立的 TCP 连接 刚装好是空的,跑上面 Java 代码后会出现一条
Channels 连接之上的通道 有 Connection 后才有 Channel
Exchanges 交换机列表 已有一批内置的 amq.direct、amq.topic、amq.fanout、(AMQP default) 等
Queues 队列列表 空的,队列要自己声明
Admin 用户、虚拟主机、权限管理 只有 itcast 一个用户

这里容易困惑的一点:交换机装好就有好几个,队列却一个都没有。因为交换机有内置的默认实例,队列必须显式声明才会创建------生产者或消费者谁先声明都行,参数要一致。

新建用户与虚拟主机

Admin → Add user,填用户名、密码,再选角色(Tags):

Tag 权限
management 能登录控制台,看自己有权限的 vhost
policymaker 管理策略(镜像队列、TTL 等)
monitoring 查看节点和连接的监控数据
administrator 超级管理员,能管用户、vhost、权限

新用户建好后默认是 No access------没有分配虚拟主机,什么都干不了。这是设计如此,不是 bug。

Admin → Virtual Hosts → Add a new virtual host,名字填 /itcast(vhost 名必须以 / 开头),建好后再回到用户列表点进该用户,在 Permissions 里选择对应 vhost,Set permission 即可。

推荐的做法是一个业务/一个用户独享一个 vhost ,比如 itcast 只给 / 的权限,新用户只给 /itcast 的权限,两边谁也看不见谁的队列和交换机。这就是 RabbitMQ 的多租户隔离。
#mermaid-svg-NFmHBtFPcEL1RSUA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NFmHBtFPcEL1RSUA .error-icon{fill:#552222;}#mermaid-svg-NFmHBtFPcEL1RSUA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NFmHBtFPcEL1RSUA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NFmHBtFPcEL1RSUA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NFmHBtFPcEL1RSUA .marker.cross{stroke:#333333;}#mermaid-svg-NFmHBtFPcEL1RSUA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NFmHBtFPcEL1RSUA p{margin:0;}#mermaid-svg-NFmHBtFPcEL1RSUA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster-label text{fill:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster-label span{color:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster-label span p{background-color:transparent;}#mermaid-svg-NFmHBtFPcEL1RSUA .label text,#mermaid-svg-NFmHBtFPcEL1RSUA span{fill:#333;color:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA .node rect,#mermaid-svg-NFmHBtFPcEL1RSUA .node circle,#mermaid-svg-NFmHBtFPcEL1RSUA .node ellipse,#mermaid-svg-NFmHBtFPcEL1RSUA .node polygon,#mermaid-svg-NFmHBtFPcEL1RSUA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NFmHBtFPcEL1RSUA .rough-node .label text,#mermaid-svg-NFmHBtFPcEL1RSUA .node .label text,#mermaid-svg-NFmHBtFPcEL1RSUA .image-shape .label,#mermaid-svg-NFmHBtFPcEL1RSUA .icon-shape .label{text-anchor:middle;}#mermaid-svg-NFmHBtFPcEL1RSUA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NFmHBtFPcEL1RSUA .rough-node .label,#mermaid-svg-NFmHBtFPcEL1RSUA .node .label,#mermaid-svg-NFmHBtFPcEL1RSUA .image-shape .label,#mermaid-svg-NFmHBtFPcEL1RSUA .icon-shape .label{text-align:center;}#mermaid-svg-NFmHBtFPcEL1RSUA .node.clickable{cursor:pointer;}#mermaid-svg-NFmHBtFPcEL1RSUA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NFmHBtFPcEL1RSUA .arrowheadPath{fill:#333333;}#mermaid-svg-NFmHBtFPcEL1RSUA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NFmHBtFPcEL1RSUA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NFmHBtFPcEL1RSUA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NFmHBtFPcEL1RSUA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NFmHBtFPcEL1RSUA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NFmHBtFPcEL1RSUA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster text{fill:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA .cluster span{color:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NFmHBtFPcEL1RSUA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NFmHBtFPcEL1RSUA rect.text{fill:none;stroke-width:0;}#mermaid-svg-NFmHBtFPcEL1RSUA .icon-shape,#mermaid-svg-NFmHBtFPcEL1RSUA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NFmHBtFPcEL1RSUA .icon-shape p,#mermaid-svg-NFmHBtFPcEL1RSUA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NFmHBtFPcEL1RSUA .icon-shape .label rect,#mermaid-svg-NFmHBtFPcEL1RSUA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NFmHBtFPcEL1RSUA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NFmHBtFPcEL1RSUA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NFmHBtFPcEL1RSUA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Set permission
Set permission
看不见
用户 itcast
virtualHost: /
用户 李四
virtualHost: /itcast
exchange / queue 组 A
exchange / queue 组 B

安装排障

按现象查,别瞎猜:

现象 常见原因 怎么查 / 怎么修
Bind for 0.0.0.0:15672 failed: port is already allocated 端口被占用(旧容器没删、宿主机装了 RabbitMQ) `ss -tlnp
docker: Conflict. The container name "/mq" is already in use 同名容器已存在 docker rm -f mq 删掉旧的,或用新名字
容器起来又退出,docker ps -a 显示 Exited (1) 启动报错 docker logs mq 看最后几十行,多半是主机名/Erlang cookie/磁盘问题
日志报 unable to connect to epmd 或节点名对不上 主机名变了或 4369/25672 端口受限 固定 --hostname;确认容器内 hostname 命令输出与 /var/lib/rabbitmq/mnesia 下的目录名一致
日志报 insufficient free disk space 磁盘低于阈值(默认 50MB) df -h 看空间;调低阈值 -e RABBITMQ_DISK_FREE_LIMIT=256MB
浏览器打不开 15672,但 curl localhost:15672 通 防火墙 / 安全组没放 CentOS7:firewall-cmd --zone=public --add-port=15672/tcp --permanent && firewall-cmd --reload;云服务器还要开安全组
15672 完全没响应 用的镜像不带 management 插件 docker exec -it mq rabbitmq-plugins enable rabbitmq_management;根治办法是换 -management 镜像
用 guest/guest 登录失败 RabbitMQ 3.3 起 guest 只允许 localhost 访问 远程登录用 RABBITMQ_DEFAULT_USER/PASS 建的账号;非要用 guest,在容器内 echo "loopback_users = none" >> /etc/rabbitmq/rabbitmq.conf 后重启服务(仅限本地环境)
改了 -e 里的密码重启后不生效 默认账号只在初始化时写入,数据卷已存在就跳过 docker exec -it mq rabbitmqctl change_password itcast 新密码
客户端连 5672 报 ACCESS_REFUSED 账号密码错,或该用户对这个 vhost 没权限 控制台 Admin → 用户 → Permissions 检查;代码里 setVirtualHost 是否与权限匹配
控制台能看到消息,但消费者收不到 队列没绑定交换机 / RoutingKey 写错 Exchanges 页点进交换机看 Bindings;用默认交换机时 RoutingKey 必须等于队列名
容器重启后队列和消息全没了 队列非持久化 + 没挂数据卷 队列声明 durable=true、消息 MessageProperties.PERSISTENT_TEXT_PLAIN;数据目录挂 -v mq-data:/var/lib/rabbitmq

两个高频但容易忽略的点再强调一次:

一是镜像 tag 。不带 -management 的镜像没有 UI,很多人装完发现 15672 打不开,翻半天防火墙,其实是镜像选错了。

二是环境变量只在初始化生效 。RabbitMQ 的数据目录一旦有内容(mnesia 已初始化),重启时不会再读 RABBITMQ_DEFAULT_USER/PASS。改密码、改用户走 rabbitmqctl,别指望改 docker run 命令。

Linux 原生安装简述

不用 Docker 的场景(比如生产环境要求直接装在宿主机),流程是这样:

bash 复制代码
# 1. 先装 Erlang ------ 版本必须匹配 RabbitMQ 要求,这是最容易翻车的一步
#    RabbitMQ 3.8.x 需要 Erlang 21.3 ~ 23.x
#    版本对应表见官方文档 https://www.rabbitmq.com/which-erlang.html
yum install -y erlang

# 2. 导入签名 key、下载 rpm 并安装服务端
#    注意:yum 不会自己去 GitHub 找 rpm,文件必须先落到本地,否则报
#    No package rabbitmq-server-3.8.19-1.el7.noarch.rpm available.
rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.19/rabbitmq-server-3.8.19-1.el7.noarch.rpm
yum install -y rabbitmq-server-3.8.19-1.el7.noarch.rpm

# 3. 开机自启 + 启动
systemctl enable rabbitmq-server
systemctl start rabbitmq-server
systemctl status rabbitmq-server

# 4. 开启管理控制台插件(原生安装默认不装 UI)
rabbitmq-plugins enable rabbitmq_management

# 5. 建管理员账号,别用 guest 远程登录
rabbitmqctl add_user itcast 123321
rabbitmqctl set_user_tags itcast administrator
rabbitmqctl set_permissions -p / itcast ".*" ".*" ".*"

# 6. 放通端口
firewall-cmd --zone=public --add-port=5672/tcp --permanent
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload

Ubuntu / Debian 换成 apt-get install -y erlang rabbitmq-server,其余步骤一致。

两种方式对比:

Docker 部署 Linux 原生部署
前置依赖 只需要 Docker 要自己解决 Erlang 版本匹配
耗时 分钟级 十分钟到半小时,卡在依赖上更久
升级/回滚 换镜像 tag 重跑 rpm/apt 升级,回滚麻烦
多实例/集群 起多个容器即可 多套目录与配置,端口要改
适合场景 本地开发、学习、测试环境 生产环境、对资源有特殊管控要求的场景

集群部署在这两者的基础上做:多个节点共享同一个 Erlang Cookie(~/.erlang.cookie 内容必须一致),节点名 rabbit@主机名 要能互相解析,再 rabbitmqctl join_cluster 把节点加进去,最后配镜像队列策略做队列高可用。单机阶段先不用管。

命令速览

命令 作用
docker pull rabbitmq:3.8-management 拉取带控制台的镜像
docker load -i mq.tar 从本地镜像包导入
docker run ... rabbitmq:3.8-management 启动容器(见上文完整参数)
docker ps --filter name=mq 看容器状态与端口映射
docker logs -f mq 看启动日志,找 completed with N plugins
docker exec -it mq rabbitmqctl status 容器内查看节点状态
docker exec -it mq rabbitmq-plugins list 查看已启用插件
docker exec -it mq rabbitmqctl change_password 用户 新密码 改密码
docker exec -it mq rabbitmqctl list_queues 列出队列
docker stop mq / docker start mq 停止 / 重新启动容器
docker rm -f mq 强制删除容器(数据卷不会一起删)
`ss -tlnp grep -E '5672
curl -u 用户:密码 http://localhost:15672/api/overview 用 HTTP API 验证服务可用性

官方文档

总结

  • RabbitMQ 是 Erlang 写的 AMQP 实现,强项是可靠性和低延迟,不是极致吞吐;装它最省事的方式是 Docker + -management 镜像。
  • 端口分工必须记住:5672 收发消息,15672 看控制台。连错端口是新手最常见的低级错误。
  • docker run 里的 --hostname 单机可省,但一旦要保留数据或做集群就必须固定------节点名 rabbit@主机名 跟着主机名走。
  • 验证安装别只看浏览器:容器 Up → 日志 completed with N plugins → 端口监听 → HTTP API 返回 JSON → 控制台登录,五步全过才算数。
  • 多用户场景下用 virtualHost 做隔离,一个用户配一个 vhost 并单独授权,别所有人共用 /。
相关推荐
sibylyue1 小时前
SQLite 运行模式
java·jvm·sqlite
专业程序开发源1 小时前
django便利店外卖后台管理系统19650-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·django·课程设计
JAVA面经实录9171 小时前
Java高级后端 · 架构组件开发 + CodeReview(本岗位差异化核心)
java·架构·代码复审
toooooop81 小时前
宝塔Python项目管理器:环境变量踩坑记录
java·jvm·python
代码山河1 小时前
Java语言特点:跨平台、面向对象、安全性详解
java·学习·架构·教程·面向对象·项目
马剑威(威哥爱编程)1 小时前
【AI全栈后端12-09】Spring Boot 用流式输出做打字机对话:点下去不再干等
java·人工智能·spring boot·后端
步行cgn2 小时前
Spring 事务传播行为详解
java·数据库·spring
海宇服务2 小时前
零信任架构实战:基于海宇车辆vin码查车辆信息详版构建自动化汽配云仓参配核验网关
java·人工智能·架构·自动化
wno7042 小时前
Spring Boot整合Flyway
java·spring boot·后端