Skip to content

EMQX 集群

EMQX 集群是指多个 EMQX 节点协同工作,组成一个统一系统。各节点之间自动共享客户端会话、主题订阅和路由信息,实现消息的无缝传递与系统的水平扩展。

相比单节点模式需要独立处理所有连接与数据,集群架构可在节点间分担负载,在节点故障时自动重路由流量,确保服务持续可用。该架构非常适合构建大规模、关键业务的 MQTT 消息平台与物联网系统。

本章导读

本章节将全面介绍 EMQX 集群的核心概念与实践应用,包括:

无论您是构建高可用 MQTT 平台,还是准备部署生产级集群,本章节都将为您提供清晰的指导。

为什么使用 EMQX 集群

EMQX 集群适用于对可靠性、可扩展性与高性能有严格要求的大规模或关键业务系统。其主要优势包括:

  • 可扩展性:通过增加节点横向扩展系统,支持不断增长的 MQTT 客户端与消息量。
  • 高可用性:分布式架构避免单点故障,某些节点宕机时系统依然可用。
  • 负载均衡:集群中的节点可分担消息处理与连接负载,避免资源瓶颈。
  • 集中管理:支持统一的管理界面和 API,简化运维工作。
  • 数据一致性与安全性:会话和路由状态在集群节点间自动同步,确保数据一致并保障通信安全。

EMQX 集群工作原理

一个 EMQX 集群由多个节点组成,每个节点都运行一个 EMQX 实例,这些节点协同工作以路由消息、管理 MQTT 会话,并确保高可用性与可扩展性。每个节点都会与其他节点通信,分享客户端订阅和路由信息,从而确保消息能够准确传递给所有相关订阅者,无论这些订阅者连接在哪个节点上。

这种分布式架构使 EMQX 能够支持关键任务型消息系统,实现极低的停机时间与灵活的横向扩展。

集群架构演进

EMQX 5.0 之前:基于 Mnesia 的集群架构

早期版本的 EMQX 使用 Erlang/OTP 内置的 Mnesia 数据库,并采用全互联(Full-Mesh)拓扑结构。每个节点通过 Erlang 分布式协议(默认端口为 4370)与集群中所有其他节点建立直接的 TCP 连接,构成一个高度耦合的系统。

mnesia-cluster

然而,这种架构存在以下限制:

  • 节点数增加时,同步开销显著增加
  • 集群规模超过 5 个节点时,容易出现不稳定
  • 扩展性有限,通常只能通过垂直扩展(提升硬件性能)来应对

EMQX 4.3 在基准测试中可支持 1000 万并发连接,但需要进行广泛的性能调优并依赖高性能硬件。详情参见性能测试报告

EMQX 5.0 及以后:Mria + RLOG 架构

从 5.0 版本起,EMQX 引入了全新的 Mria 集群架构,支持更大规模、更稳定的集群运行。

核心改进包括:

  • 核心节点与副本节点角色分离:核心节点负责写操作和完整数据复制,副本节点则只读,负责客户端会话处理。
  • 复制日志(RLOG)机制:实现从核心节点到副本节点的异步、高吞吐数据复制。
  • 可扩展性提升:单个集群可支持高达 1 亿个 MQTT 连接。
EMQX_cluster

注意

集群功能在试用期内可用,但一旦试用期结束,您需要购买商业 License 才能继续使用该功能。没有有效的商业 License,试用期结束后,集群功能将被禁用。

为了支持这一架构,EMQX 基于 Erlang/OTP 平台,并借助一套内部数据结构来完成消息路由与投递。接下来的支撑 EMQX 集群的 Erlang/OTP 架构集群数据结构小节将详细介绍这些运行机制。

支撑 EMQX 集群的 Erlang/OTP 架构

EMQX 基于 Erlang/OTP 平台开发,这是一个最初为构建分布式电信系统而设计的运行时系统与框架。在 Erlang 中,每个运行实例被称为一个节点(Node),其名称格式为 <name>@<host>,例如:emqx1@192.168.0.10

Erlang 节点通过 TCP 连接并使用轻量级的消息传递进行通信。这种机制构成了 EMQX 集群通信的基础。所有集群节点必须使用相同的 Cookie 以完成认证。一旦连接建立并认证通过,该节点即可自动加入集群。在 EMQX 5.x 中,节点的角色(核心或副本)会决定它在数据复制与路由中的职责。

集群数据结构

为了在分布式集群中高效路由消息,EMQX 使用三种关键内部数据结构:订阅表、路由表和主题树。这些结构协同工作,确保消息即使在跨节点传输的情况下也能被正确投递给订阅者。

订阅表(分区存储)

每个 EMQX 节点维护一个本地订阅表,用于记录直接连接到该节点的客户端订阅信息。数据是分区存储的,因为每个节点仅保存自身客户端的订阅信息,从而减少了集群的同步负担并提升扩展性。

当消息被路由到某个节点时,该节点会查找本地订阅表以确定哪些客户端应接收该消息。

示例结构:

node1:
    topic1 -> client1, client2
    topic2 -> client3

node2:
    topic1 -> client4

该示例说明了同一个主题(如 topic1)可在多个节点上拥有订阅者,而每个节点独立管理自身的映射关系。

路由表(由核心节点复制)

路由表记录了哪些主题在哪些节点上被订阅。在 EMQX 5.x 中,该表由核心节点维护并复制到所有节点。副本节点仅保留只读副本,这些数据通过 RLOG 同步机制传输。

当客户端在副本节点上发起订阅时,该事件会被上报给核心节点,由其更新全局路由表,并同步到其他节点。

示例结构:

topic1 -> node1, node2
topic2 -> node3
topic3 -> node2, node4

主题树(由核心节点复制)

主题树是一种分层结构,用于匹配发布的主题与订阅模式(包括 MQTT 通配符 +#)。它帮助 EMQX 高效处理复杂的主题过滤逻辑。

与路由表类似,主题树由核心节点构建并同步至所有副本节点。当客户端(如 client1)订阅 t/+/x 时,该订阅模式将被添加至主题树,并在全集群中同步更新。

主题订阅关系示例:

客户端节点订阅主题
client1node1t/+/x, t/+/y
client2node2t/#
client3node3t/+/x, t/a

在这些订阅建立后,EMQX 将构建如下的主题树与路由表:

image

消息分发流程

当一个 MQTT 客户端发布消息时,它所在的节点(无论是核心还是副本)使用主题树匹配消息主题与所有订阅模式,同时查找路由表,并根据消息主题将消息转发到对应的节点(可能是多个节点)。然后,接收到消息的节点会查找本地订阅表,并将消息发送至对应的订阅者。

例如,当客户端 1 发布一条消息到主题 t/a 时,消息在节点之间的路由和分发如下:

  1. 客户端 1节点 1 发布一条主题为 t/a 的消息;
  2. 节点 1 查询主题树,了解到 t/a 与现有主题 t/at/# 相匹配。
  3. 节点 1 查询路由表,并得知:
    • 节点 2 上有客户端订阅了 t/# 主题;
    • 节点 3 上有客户端订阅了 t/a 主题;因此节点 1 会将消息同时转发给节点 2节点 3
  4. 节点 2 收到转发的 t/a 消息后,通过查询本地订阅表,将消息分发给订阅了 t/# 的客户端。
  5. 节点 3 收到转发的 t/a 消息后,通过查询本地订阅表,将消息分发给订阅了 t/a 的客户端。
  6. 消息发布完成。

如需进一步了解 EMQX 集群设计,请参见 EMQX 集群设计

集群特性概览

EMQX 基于其自研的 Ekka 库扩展了 Erlang 原生的分布式机制,提供了一整套先进的集群能力。通过 Ekka 提供的抽象层,EMQX 实现了自动节点发现、动态集群组建、网络分区处理、节点清理等关键特性。

节点发现与自动集群

EMQX 支持多种节点发现机制,可在不同的部署环境中实现自动集群:

策略描述
手动通过手动命令创建一个集群
静态基于静态节点列表的自动集群
DNS基于 DNS A 和 SRV 记录的自动集群
etcd通过 etcd 的自动集群
k8s基于 Kubernetes 服务的自动集群

详细说明请参阅:创建与管理集群

网络分区自动修复

EMQX 提供网络分区自动修复功能,在发生网络分区时可自动恢复集群,无需人工干预,适用于对高可用性有严格要求的关键业务场景。

该功能由 cluster.autoheal 参数控制,默认启用:

bash
cluster.autoheal = true

启用后,EMQX 会持续监测集群内节点之间的连接状态。当检测到网络分区时,会隔离受影响的节点,并继续使用剩余节点对外提供服务。一旦网络恢复,系统会自动将被隔离的节点重新加入集群。

集群节点自动清理

EMQX 支持自动清理离线节点的功能,可在配置的时间间隔后自动将断开连接的节点移出集群,从而避免长期离线节点影响集群性能。

该功能默认启用,由 cluster.autoclean 参数控制,默认时间间隔为 24 小时:

bash
cluster.autoclean = 24h

跨节点会话保持

在 EMQX 集群模式下,MQTT 客户端的持久会话支持跨节点保持与迁移,确保连接切换时会话状态不丢失。

启用方法如下:

  • MQTT 3.x 客户端:设置 clean_start = false
  • MQTT 5.0 客户端:设置 clean_start = falsesession_expiry_interval > 0

启用后,当客户端断开连接时,EMQX 会保留其与 Client ID 关联的会话信息。客户端重新连接后,EMQX 会恢复之前的会话,投递断开期间积压的消息,并保留原有订阅。

例如负载均衡的两台集群节点: node1 与 node2,同一 MQTT 客户端先连接 node1,node1 节点会创建持久会话;客户端断线重连到 node2 时,MQTT 的连接在 node2 节点,持久会话仍在 node1 节点。

这一机制确保客户端在连接节点变化时,仍能收到离线期间缓存的消息,并保持订阅状态不变。

网络要求

为确保集群性能,EMQX 要求集群节点之间的网络延迟低于 10 毫秒;若延迟超过 100 毫秒,集群可能无法正常运行。

建议将核心节点部署在同一私有网络中。在 Mria+RLOG 架构下,也推荐将副本节点部署在同一私有网络内。

下一步:创建 EMQX 集群

您可继续阅读以下章节了解如何创建 EMQX 集群。