emqx linux分布式部署的核心是节点发现、元数据共享、统一认证与消息路由;需确保erlang cookie一致、防火墙开放4369及6369-7369端口、时间同步,并验证cluster status、跨节点客户端列表和跨节点mqtt收发。

直接上结论:EMQX 在 Linux 上做分布式部署,核心不是“装多个实例”,而是让节点能互相发现、共享元数据、统一认证和路由消息。单节点跑起来容易,但一上分布式,cluster.discovery 配置错一个参数、防火墙漏开一个端口、或 Erlang cookie 不一致,整个集群就卡在 joining 状态不动——这不是 bug,是 Erlang 分布式机制的刚性要求。
怎么确认 EMQX 节点间真正组成了集群
别只看 sudo emqx_ctl cluster status 输出里有没有其他节点名。真实情况是:节点可能“列在列表里”,但实际无法同步会话、无法跨节点投递 QoS 1 消息、Dashboard 显示不同步的连接数。必须验证三件事:
- 执行
sudo emqx_ctl cluster status,所有节点状态必须是Running(不是Joining或Down) - 在任意节点执行
sudo emqx_ctl clients list,结果应包含全部节点上的客户端连接(不是只显示本机的) - 用 MQTT 客户端订阅
test/topic,从另一台机器发布消息,确保能实时收到——且发布和订阅不在同一节点上(可用sudo emqx_ctl listeners show查每个节点监听的 IP)
emqx.conf 里最关键的三个分布式配置项
EMQX 5.x 默认使用 static 发现方式,但生产环境强烈建议改用 etcd 或 k8s。如果硬要用 static,这三个配置必须逐字核对:
-
cluster.discovery = static:必须显式设置,不能依赖默认值 -
cluster.static.seeds = emqx@192.168.1.10,emqx@192.168.1.11:注意是emqx@IP格式,不是域名;IP 必须是节点间可直连的内网地址;所有节点的 seeds 列表要完全一致 -
node.name = emqx@192.168.1.10:每个节点必须唯一,且与 seeds 中的条目严格匹配;不能写成emqx@localhost或emqx@hostname(除非 /etc/hosts 已精确映射)
改完配置后,必须重启节点:sudo systemctl restart emqx,不能只 reload。
为什么集群启动后总卡在 Joining 状态
这是最常踩的坑,原因几乎都出在底层通信层:
- Erlang cookie 不一致:所有节点的
/var/lib/emqx/.erlang.cookie文件内容必须**完全相同**(包括空格和换行),且权限为400,属主是emqx用户 - 防火墙阻断了 Erlang 分布式端口:EMQX 默认用
4369(epmd 端口) + 动态端口范围(默认6369-7369)。云服务器安全组和本地ufw/firewalld都得放行这两个范围 - 节点时间不同步:Erlang 集群对时钟漂移敏感,误差超过 1 秒可能导致握手失败。务必在所有节点运行
sudo timedatectl set-ntp true并验证timedatectl status显示 “System clock synchronized: yes”
分布式下认证和 ACL 必须集中管理
单节点时把用户写进 etc/plugins/emqx_auth_username.conf 就能用,但分布式下这么做会导致各节点认证不一致——A 节点加了用户,B 节点查不到。正确做法只有两种:
- 用内置数据库:启用
emqx_auth_mnesia插件,所有节点共享同一份内存数据库(适合中小规模,节点数 ≤ 5) - 对接外部系统:生产环境必须用
emqx_auth_http或emqx_auth_jwt,把认证逻辑交给你的业务后端或 Keycloak 等统一身份服务
ACL 规则同理,不要分散写在各节点配置里。ACL 文件路径(如 etc/acl.conf)在集群中会被所有节点读取,但修改后需手动触发重载:sudo emqx_ctl acl reload,否则新规则不生效。
真正难的不是启动集群,而是让所有节点对“当前谁在线、谁订阅了什么、消息该往哪转”达成一致。这个一致性靠的是 Erlang 的底层分布协议,它不给你容错余地——cookie 错一位、时间差半秒、端口少开一个,集群就静默失败。部署前先用两台干净虚拟机跑通最小闭环,比在生产环境反复重启强得多。











