RocketMQ Dashboard 部署、链路观察与权限治理工具手册
页面能打开,集群为什么仍然是一片空白
RocketMQ Dashboard 启动日志显示 Web 服务正常,浏览器也能打开首页,但 Cluster、Topic 和 Consumer 都没有数据。有人把 rocketmq.namesrv.addr 写成 127.0.0.1:9876,却忘了 Dashboard 正在容器里运行;也有人把 5.x Proxy 的 8081 当成 Dashboard 的管理入口,结果越改越远。
先把调用链画清楚:Dashboard 的管理客户端通过 NameServer 获取路由,再直接访问 Broker 的管理接口。Proxy 是 5.x 客户端接入端点,不是 Dashboard 发现和管理 Broker 的替代入口。Dashboard 2.1.0 虽然有 proxyAddr 配置,用于部分面向 Proxy 的能力,但 Topic、consumer group、Broker 配置和运行信息仍依赖 NameServer 与 Broker 可达。
这条链路决定了排障顺序:先证明 Dashboard 容器能解析并连接 NameServer,再检查 NameServer 返回的 Broker 地址是否从 Dashboard 网络可达,最后才看 ACL、TLS、版本兼容和具体页面功能。
发行版本和兼容关系不能靠 latest 猜
Apache RocketMQ Dashboard 有独立的 发行页面。2.1.0 是可下载的发行版本;其构建文件使用 RocketMQ 5.3.3 客户端依赖,并包含多项 5.x 消息查询与页面修复。它不等于“对所有后续 Broker 版本自动兼容”。连接 RocketMQ 5.5.x 或更高发行线前,要在测试集群验证 Topic、consumer、消息查询、轨迹、ACL 和 offset 操作,不能只以首页可打开作为兼容证据。
官方 Dashboard 操作说明 仍展示 apacherocketmq/rocketmq-dashboard:latest。共享环境不应长期跟随 latest:可以从 2.1.0 源码构建团队镜像,也可以先拉取官方镜像、记录解析后的 digest,再用 digest 部署。这样回滚时恢复的是同一份二进制,而不是标签后来指向的新镜像。
docker pull apacherocketmq/rocketmq-dashboard:latest
docker image inspect apacherocketmq/rocketmq-dashboard:latest \
--format '{{index .RepoDigests 0}}'将输出的 repository@sha256:... 写入部署变量或制品清单。不要把示例 digest 写死进公共模板,因为不同平台架构和重新发布会产生不同结果。
在同一容器网络中启动 Dashboard
假设 NameServer、Broker 和 Proxy 已在外部网络 dev-rocketmq 中运行,服务名分别为 rmqnamesrv、rmqbroker 和 rmqproxy。先从临时容器验证网络:
docker run --rm --network dev-rocketmq busybox:1.37 sh -c \
"nslookup rmqnamesrv && nc -vz rmqnamesrv 9876 && nc -vz rmqbroker 10911"两个 TCP 连接都成功后再启动 Dashboard。只连通 9876 不够:NameServer 可以返回一个宿主机 IP、错误的 brokerIP1 或容器外不可达地址,页面仍会在读取 Broker 数据时失败。
最小容器启动
Dashboard 2.1.0 源码默认 Web 端口是 8082。为了避免与 Proxy 的 8080/8081 混淆,将宿主机端口映射为 18082,并只绑定回环地址:
services:
rocketmq-dashboard:
image: ${ROCKETMQ_DASHBOARD_IMAGE:?pin image or digest}
container_name: rocketmq-dashboard
restart: unless-stopped
ports:
- "127.0.0.1:18082:8082"
environment:
JAVA_OPTS: >-
-Drocketmq.namesrv.addr=rmqnamesrv:9876
-Drocketmq.config.proxyAddr=rmqproxy:8080
-Drocketmq.config.isVIPChannel=false
-Drocketmq.config.timeoutMillis=5000
-Drocketmq.config.loginRequired=false
networks:
- dev-rocketmq
networks:
dev-rocketmq:
external: true本机 .env 中只保存镜像引用:
ROCKETMQ_DASHBOARD_IMAGE=apacherocketmq/rocketmq-dashboard@sha256:replace_with_inspected_digestrocketmq.namesrv.addr 是 RocketMQ 客户端识别的 NameServer 系统属性;rocketmq.config.proxyAddr 不会替代它。isVIPChannel=false 让 Dashboard 使用 Broker 主端口而不是减 2 后的 VIP 端口,容器网络中可减少 10909 未暴露造成的误判;若团队明确启用 VIPChannel,则要同时验证对应端口。timeoutMillis 过小会把慢网络误报成 Broker 故障,过大则让页面请求长时间挂起。
启动并观察:
docker compose up -d
docker compose ps
docker compose logs --tail=160 rocketmq-dashboard
curl -I http://127.0.0.1:18082打开 http://127.0.0.1:18082 后,Cluster 页面应出现 cluster、broker name、broker id 与地址;Topic 页面应能看到系统 Topic 和测试 Topic。若只有首页成功,不能判定接入完成。
从发行源码构建可追溯镜像
不希望依赖 latest 时,从 2.1.0 source release 构建 JAR。源码要求 JDK 17;构建前验证签名或校验和,然后运行:
mvn -DskipTests clean package
java -jar target/rocketmq-dashboard-2.1.0.jar实际 JAR 名称以构建产物为准,可用 ls target/*.jar 确认。团队镜像应采用非 root 用户、只读根文件系统、固定 JRE 基础镜像并暴露 8082,同时把 Dashboard 的数据目录单独挂载。构建日志、源码 tag、依赖清单和镜像 digest 应进入制品记录,便于漏洞响应与回滚。
关键配置如何改变运行行为
Dashboard 2.1.0 的核心配置位于 rocketmq.config。这些字段应作为变更项评审:
| 字段 | 影响 | 错误时的典型现象 |
|---|---|---|
namesrvAddrs / rocketmq.namesrv.addr | 路由发现入口,可配置多个集群地址 | 首页可开,Cluster/Topic 为空或连接 localhost:9876 |
isVIPChannel | 是否访问 Broker VIP 端口 | NameServer 正常,Broker 管理请求连接被拒绝 |
timeoutMillis | 管理请求超时 | 网络稍慢时频繁超时,或故障页面长时间挂起 |
dataPath | 监控数据、登录用户等本地状态目录 | 重启后状态丢失,或只读文件系统启动失败 |
enableDashBoardCollect | 是否采集 Dashboard 统计数据 | 关闭后部分图表无历史统计;开启会增加请求与本地数据 |
loginRequired | 是否启用 Dashboard 登录 | 默认关闭会让任何可达者访问管理面 |
authMode | file 或 acl 登录策略 | 用户文件/ACL 配置不匹配时无法登录或权限异常 |
useTLS | Dashboard 管理客户端是否使用 TLS | 与 Broker TLS 设置不一致时握手失败 |
proxyAddr / proxyAddrs | Proxy 地址 | 部分 5.x Proxy 相关能力失败,不应误判为 NameServer 配置 |
accessKey / secretKey | Dashboard 调用 RocketMQ 的 ACL 身份 | 认证失败,或使用高权身份扩大误操作半径 |
多集群接入要避免在 OPS 页面随意改地址。把集群地址写进受控配置,实例按环境隔离;否则一次页面操作就可能把整个团队从测试集群切到生产集群,后续截图和操作也失去可追溯性。
Topic、Consumer、消息与轨迹怎么形成排障证据
Topic 页面先看路由,不先点修改
选择一个专用测试 Topic,例如 project_a_dashboard_probe,核对:
Topic 分布在哪些 Broker。每个 Broker 的读写队列数是否符合预期。路由地址是否是 Dashboard 网络可达地址。
权限字段是否允许当前测试身份执行查询。
如果 Topic 在 mqadmin topicList 中可见、Dashboard 却不可见,比较两者使用的 NameServer、ACL 身份和 VIPChannel。不要直接在页面“重新创建”同名 Topic;错误的队列数或 Broker 选择会变成真实元数据变更。
Consumer 页面把堆积拆到队列
总堆积只是入口。选择目标 consumer group 后记录每个 message queue 的 broker、queue id、broker offset、consumer offset、diff 和在线 client。若只有单个 queue 的 diff 增长,优先检查该队列对应的消费线程、热点 key 或异常消息;若所有 queue 都增长,再看消费者是否整体离线或下游变慢。
用 CLI 交叉验证:
sh bin/mqadmin consumerProgress \
-n rmqnamesrv:9876 \
-g project_a_dashboard_probe_groupDashboard 与 CLI 都显示相同 group 和趋势,才证明页面数据可信。页面刷新时刻不同会产生小幅差异,但不应连接到不同 cluster 或返回完全不同的队列集合。
消息查询不是全量检索引擎
消息页面通常按 message id、key、Topic 和时间条件查询。消息能否被找到受索引、保留、Broker 路由和版本能力影响;“页面搜不到”不能直接推断消息从未发送。正向探针应使用脱敏测试 Topic,发送带唯一 key 的小消息:
topic=project_a_dashboard_probe
key=dashboard-probe-001
body={"probe":"dashboard-probe-001","kind":"synthetic"}先保存生产者返回的 message id、queue id 和发送状态,再分别用 message id 和 key 查询。预期页面展示同一 Topic、key、存储时间、Broker 和消息属性。若按 key 查不到但按 id 能找到,检查 key 索引和查询条件,不要重复发送大量探针污染 Topic。
轨迹需要生产、消费两侧真的上报
Dashboard 能展示消息轨迹,不代表集群天然拥有完整 trace。生产者、消费者、Broker 和 trace Topic 配置必须匹配,采集链路也要有权限。轨迹缺失时按“发送结果存在 -> 消息存储可查 -> 消费进度变化 -> trace Topic 有数据 -> Dashboard 有查询权限”的顺序排查。
轨迹只说明 RocketMQ 客户端链路中的已记录事件,不能替代业务幂等记录、下游数据库提交证据或分布式追踪。消费成功轨迹与业务落库失败可以同时发生,这正是架构排障不能只看绿色页面的原因。
正向实验:观察一条可控消息的完整路径
在隔离测试集群执行:
用 mqadmin 创建测试 Topic 和测试 consumer group,记录命令输出。启动测试消费者,但让它先暂停业务处理或返回可识别日志。发送一条带唯一 key 的虚构消息,保存 message id。
在 Dashboard 的 Topic 页面确认路由,在 Message 页面按 id/key 查到消息。在 Consumer 页面确认 group 在线,并观察消费前后的 diff。若启用了 trace,再核对发送和消费轨迹。
预期不变量是:Topic 路由一致,message id 与 key 指向同一条消息,消费后对应队列的 consumer offset 前进,diff 回落。若只看到“发送成功”而 offset 不变,问题仍在消费链路;若 offset 前进但业务结果缺失,应转向消费者事务和下游系统证据。
实验清理要按对象执行:停止测试消费者,删除测试 group,再删除测试 Topic。删除前确认名称完全匹配测试前缀,并保存操作对象列表。不要在共享集群运行模糊匹配删除,也不要清理 %RETRY%、%DLQ% 或系统 Topic 时猜测归属。
反向实验:证明控制台不会把错误藏起来
NameServer 地址写成容器内 localhost
将测试实例的地址临时改为 127.0.0.1:9876。预期 Web 首页仍可返回,但 Cluster/Topic 请求失败,日志出现 NameServer 连接拒绝或超时。恢复 rmqnamesrv:9876 后重新验证 Cluster 和 Topic;这个实验说明 HTTP 健康不等于 RocketMQ 健康。
Broker 公布不可达地址
保持 NameServer 可达,让测试 Broker 的 brokerIP1 公布 Dashboard 容器不可达的地址。预期 Topic 路由可能出现,但读取 Broker 配置、consumer 进度或消息时失败。修复 brokerIP1 后从 Dashboard 容器对 10911 做 TCP 验证,再刷新页面。
ACL 身份只允许查询
给 Dashboard 专用身份配置 Cluster:Get,List、目标 Topic:Get,List 和 Group:Get,List 等读取权限,不给 Create、Update、Delete、Pub、Sub。正向查看应成功;创建 Topic、发送消息、删除 group、重置 offset 必须返回授权拒绝。具体 ACL 2.0 动作以 Access Control 2.0 的目标 RocketMQ 发行线为准。
若页面隐藏按钮但管理请求仍能成功,说明只有前端限制;若页面显示按钮而 Broker 拒绝,说明后端 ACL 正在兜底,但用户体验与角色配置仍需修正。最终状态应是两层都拒绝。
错误 Dashboard/Broker 版本组合
在测试实例连接目标 Broker 发行线,逐项执行 Topic 列表、consumer 进度、message id 查询、key 查询和 ACL 查询。若某一接口报反序列化、未知请求码或字段错误,而 CLI 正常,保留 Dashboard 与 Broker 版本、请求页面和日志堆栈,回退到已验证组合。不能用“其他页面能用”掩盖局部协议不兼容。
登录不等于只读:Dashboard 自身权限的深坑
RocketMQ 的 安全说明 明确提示 Dashboard 默认没有强认证,任何能访问 HTTP 端口的人都可能读取集群元数据。最小防线是仅绑定内网或回环地址,再由 VPN、Ingress 或反向代理提供 TLS、OIDC/Basic、IP allow-list 和访问日志。
Dashboard 2.1.0 自身支持 loginRequired,authMode 可选 file 或 acl。文件登录的用户格式包含 Normal 与 Admin 角色,但默认 Normal 权限文件并非严格只读:它允许查询之外,还可能包含发送测试消息和死信重投接口。这意味着“创建一个 Normal 用户”不能直接满足只读要求。
共享实例要执行三层收口:
在反向代理或身份网关完成用户认证和访问审计。调整 Dashboard role-permission.yml,从观察角色删除发送、重投、创建、修改、删除和 offset 操作路径。Dashboard 访问 RocketMQ 使用只读 ACL 身份,让 Broker 拒绝所有写请求。
只读角色可从查询路径白名单开始,而不是从 Admin 权限做黑名单删减:
rolePerms:
Normal:
- /rocketmq/*.query
- /ops/*.query
- /dashboard/*.query
- /topic/*.query
- /producer/*.query
- /message/*.query
- /messageTrace/*.query
- /monitor/*.query
- /consumer/*.query
- /cluster/*.query
- /dlqMessage/*.query
- /acl/*.query这仍需逐版本验证接口路径,不能假设后缀为 .query 就绝对无副作用。部署后用 Normal 用户尝试发送消息、重投 DLQ、创建 Topic、删除 group 和重置 offset,所有动作都应被 Dashboard 或 Broker 拒绝。
authMode: acl 会把用户身份与 RocketMQ ACL 结合,但 Dashboard 的 HTTP 暴露面、会话安全和角色路径仍然存在。不要把 Broker ACL 当成 Web SSO,也不要把超级用户 access key 直接写进 Compose。凭据应从 Secret 注入,定期轮换,并在访问日志中关联到操作人。
NameServer、Broker、Proxy 和 TLS 的故障分型
Cluster 页面完全为空
先看 Dashboard 日志中的目标地址,再从容器执行 DNS/TCP 验证。若 9876 不通,处理网络或 NameServer;若通但认证失败,检查 ACL/TLS;若 NameServer 返回路由后 Broker 不通,检查 brokerIP1、VIPChannel 和防火墙。
Topic 可见,Consumer 或消息查询失败
这通常说明 NameServer 和部分 Broker 管理请求已通。继续核对目标 Broker、consumer group 是否在线、Dashboard ACL 是否包含 group/Topic 查询、消息索引是否存在,以及 Dashboard 与 Broker 版本。不要退回“重启所有组件”的无差别操作。
Proxy 可用,Dashboard 却不可用
业务客户端通过 Proxy 成功,只证明 Proxy 到 NameServer/Broker 的链路正常。Dashboard 自己仍需直接访问 NameServer 和 Broker。比较两者所在网络、DNS 和证书信任,不要把 proxyAddr 填成唯一地址后删除 NameServer 配置。
TLS 开启后全部超时
区分 TCP 超时和 TLS 握手失败。TCP 不通先处理网络;握手失败检查 Dashboard useTLS、Broker TLS 模式、证书信任、主机名和协议。不要通过关闭证书校验把测试修复带入共享环境。
高可用、容量和成本怎么取舍
Dashboard 下线不会阻断 RocketMQ 生产消费,所以它的可用等级应低于消息集群本身。开发环境一个实例即可;共享实例可运行两个副本,但登录会话、本地 dataPath、统计采集和用户文件必须有明确策略。若每个副本都开启统计采集,对 Broker 的管理请求和本地存储都会成倍增加。
容量评估至少记录 cluster 数、Broker 数、Topic 数、consumer group 数、消息查询频率、轨迹量、页面并发、采集周期和本地数据保留。出现 Dashboard CPU 或堆内存持续升高时,先确认是否有人做大时间窗口消息查询、重复刷新海量 Topic、导出 DLQ 或连接多个大集群;不要把控制台扩容当成消息集群扩容问题。
共享 Dashboard 的隐性成本包括:HTTP 网关和身份接入、凭据轮换、日志与审计保留、版本兼容测试、漏洞修复、值班误操作响应,以及统计采集给 Broker 带来的额外负载。若只为一次故障临时查看,CLI 加受控跳板机可能更轻;若多人长期使用,集中治理的 Dashboard 才有价值。
升级、回滚和长期治理
每次升级都建立同一组证据:
记录旧、新 Dashboard 版本与镜像 digest,以及 RocketMQ Broker、Proxy 发行线。在隔离集群验证 NameServer 发现、Broker 管理、Topic、consumer、message id/key、trace 和 ACL。用只读身份执行正向查看,再执行创建、发送、重投、删除和 offset 反例。
检查角色路径、登录模式、数据目录和配置字段是否变化。观察管理请求量、Dashboard 堆内存、错误率和 Broker 端管理请求延迟。
回滚包必须包含旧镜像 digest、旧配置、角色权限文件和 Secret 版本引用。若新版本出现兼容错误,先切回旧实例并恢复只读服务身份;排障期间临时授予的管理员权限要在回滚后立即撤销。
团队还应明确:Dashboard owner 负责版本、入口和角色;RocketMQ owner 负责 ACL 和兼容矩阵;业务 owner 负责消息重放、offset 和 DLQ 操作的业务批准;安全 owner 负责入口认证、日志、凭据和敏感消息治理。没有责任边界时,一个“方便查看”的页面很快会变成无人负责的生产管理面。
清理本地 Dashboard
停止容器前保存需要的测试证据,然后执行:
docker compose down --remove-orphans若挂载了 dataPath,先确认其中只有 Dashboard 统计和本机登录数据,再删除对应目录。随后撤销测试 ACL 用户、删除测试 Topic/group,并检查反向代理或防火墙没有遗留 18082 入口。不要删除 NameServer、Broker、Proxy 的数据卷,也不要用 Dashboard 的批量按钮代替逐对象确认。
一次可信接入应满足这些不变量:关闭 Dashboard 不影响消息收发;Dashboard 能从 NameServer 发现正确 Broker;Proxy 与 Dashboard 管理链路不再混淆;观察角色能查看 Topic、group、堆积和脱敏探针;发送、重投、创建、删除和 offset 操作均被拒绝;镜像、配置、ACL 和回滚版本都可追溯。
