前言:为什么生产环境需要 EMQX 集群?

在正式的生产环境中,单一服务节点是脆弱的,它无法抵御硬件故障或流量激增带来的风险。“集群” 是构建一个健壮、可靠系统的基石。通过将多个 EMQX 节点组成集群,您的业务将获得:

  • 极致的高可用性: 单个节点宕机,其他节点能无缝接管,业务不中断。
  • 强大的水平扩展能力: 面对海量设备连接和消息洪流,只需向集群中添加新节点即可线性提升系统容量。
  • 简化的运维管理: 在集群任意节点上,都可以查看和管理整个集群的状态。

本指南将作为一份权威的最佳实践,手把手带您使用 Docker Compose 在多台服务器上构建一个真正稳定、高效、可扩展的 EMQX 5.0 生产级集群。


一、规划您的部署

在动手之前,合理的规划是成功的关键。请根据您的业务需求,评估以下几点。

1. 版本选择
  • EMQX 版本: 本指南基于 EMQX 5.0 及更高版本。EMQX 5.0 对集群架构进行了重大升级,与 4.x 版本不兼容。
  • 镜像标签: 我们强烈建议您使用明确的、最新的稳定版标签,例如 emqx/emqx:5.7.2,而不是 latest。这可以保证集群中所有节点的版本完全一致,并避免因自动更新导致的不确定性。
  • 版本一致性: 集群中的 所有节点都必须使用相同版本 的 EMQX 镜像,例如,所有节点都应为 5.7.2 版本,不能混合使用 5.7.1 和 5.7.2。
2. 硬件与网络要求

硬件配置直接影响集群的性能和容量。以下是基于典型场景的建议:
以下数据展示了在特定场景下,单个 EMQX 节点所能承载的连接数及其对应的硬件配置。在规划集群时,您可以将集群的总容量视为各个节点容量的总和。

配置类型CPU (vCore)内存 (RAM)磁盘适用场景
最低推荐2 核4 GB20GB SSD开发、测试、小型生产项目 (万级连接)
标准生产4 核8 GB50GB+ SSD中型生产项目 (十万到百万级连接)
大规模生产8+ 核16+ GB100GB+ SSD大规模、高吞吐量项目 (百万级以上连接)

参考:EMQX 大规模 WebSocket 并发性能测试

网络要求 (至关重要):

  • 低延迟、高带宽: 集群节点之间需要频繁地进行心跳检测和数据同步。请确保节点部署在同一个数据中心或 VPC 内,网络延迟应 低于 10ms。
  • 网络隔离: 生产环境的服务器应部署在安全的内网中,仅对外暴露必要的服务端口。

二、环境准备:打造稳固的基石

在开始部署之前,请确保所有计划加入集群的服务器上都已安装好以下两个核心工具:

  • Docker:一个轻量级的“集装箱”技术,确保 EMQX 在任何服务器上都拥有一致的运行环境。
  • Docker Compose:一个强大的“集装箱编排工具”,让我们能通过一个简单的配置文件,轻松定义和管理 EMQX 服务。
步骤 1:安装 Docker 和 Docker Compose

我们提供两种安装方式:官方分步安装和一键脚本安装。

方式一:官方推荐安装(最稳定)

我们 首要推荐 您遵循 Docker 官方文档进行安装,这是最安全、最稳定的方法,可以确保您获得最新的特性和安全更新。

  1. 安装 Docker Engine:

    官方安装指南: https://docs.docker.com/engine/install/

  2. 安装 Docker Compose:

    # 从官方 GitHub Release 页面下载最新稳定版
    sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    
    # 授予执行权限
    sudo chmod +x /usr/local/bin/docker-compose
    

方式二:一键脚本安装(国内用户推荐)

如果您在国内服务器上操作,或者觉得官方步骤比较繁琐,可以使用以下由国内镜像源提供的一键安装脚本。它可以自动为您完成 Docker 和 Docker Compose 的安装,非常便捷。

# 执行此命令将自动安装 Docker 和 Docker Compose
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)

⚠️ 安全须知

这种 curl | bash 的方式意味着您将直接下载并以管理员权限执行来自第三方服务器的脚本。请确保您信任脚本的来源 (linuxmirrors.cn)。对于安全性要求极高的生产环境,我们依然建议您优先选择方式一,通过官方渠道进行安装。


步骤 2:验证安装

无论您使用哪种方式安装,最后都需要进行验证。在每台服务器的终端中执行以下命令,如果能成功返回版本号,则代表您的环境已准备就绪。

docker --version
# 预期输出: Docker version xxx, build ...

docker-compose --version
# 预期输出: Docker Compose version xxx

三、核心架构:构建多主机高可用集群

我们的目标是在两台或多台独立的服务器上构建一个真正的高可用集群。

关键架构决策:host 网络模式

我们将使用 Docker 的 host 网络模式。这意味着容器将不再拥有独立的内部 IP,而是直接共享宿主机的网络,对外暴露的就是服务器的真实 IP 地址。

为什么选择 host 模式?

  • 性能最优: 网络通信无额外开销,接近裸机性能。
  • 配置最简: 无需复杂的网络配置,节点间可以直接通过服务器 IP 发现和通信,非常直观。
  • 稳定性高: 这是经过生产环境广泛验证的、最可靠的 Docker 集群组网方案之一。
⚠️ 关键前提:配置防火墙

这是部署过程中最容易出错的一步! 为了确保集群正常工作,您必须配置防火墙(或云服务商的安全组),放行以下端口的访问规则:

集群内部通信端口 (节点之间必须互通):

端口协议源地址 (Source)目标地址 (Destination)用途说明
4370TCP集群内任一节点 IP集群内所有其他节点 IPepmd 端口,用于 Erlang 节点服务发现。
5370TCP集群内任一节点 IP集群内所有其他节点 IPEMQX 5.x 节点间 RPC 和数据同步的核心端口。

对外服务端口 (根据需要对客户端或管理员开放):

端口协议源地址 (Source)目标地址 (Destination)用途说明
1883TCP0.0.0.0/0 (或指定客户端 IP)所有节点 IP默认的 MQTT 服务端口。
8883TCP0.0.0.0/0 (或指定客户端 IP)所有节点 IPTLS/SSL 加密的 MQTT 服务端口。
18083TCP0.0.0.0/0 (或指定管理员 IP)所有节点 IPEMQX Dashboard HTTP 管理控制台端口。

四、部署实践:构建与扩展集群

我们将以一个典型的三节点集群为例,它兼具高可用性和良好的扩展性。在生产环境中,推荐使用奇数个节点(如 3, 5, 7),这有助于在网络分区等极端情况下维持集群的决策一致性。

  • 服务器 A (节点1): IP 地址为 192.168.0.240
  • 服务器 B (节点2): IP 地址为 192.168.0.188
  • 服务器 C (节点3): IP 地址为 192.168.0.189
步骤 1: 部署初始节点

在 服务器 A, B, C 上分别创建 docker-compose.yml 文件。

在 服务器 A, B, C 上分别创建 docker-compose.yml 文件。这三个文件的内容几乎完全一样,唯一的区别在于 EMQX_NODE__NAME 环境变量的值。

文件 1: 在服务器 A (192.168.0.240) 上创建 docker-compose.yml

version: '3.8'

services:
emqx-node: # 服务名称统一,方便管理
 image: emqx/emqx:5.7.2 # 使用明确的版本号
 container_name: emqx # 容器名称统一
 restart: always
 network_mode: "host"
 environment:
 # 唯一的不同点:节点名称必须设置为当前主机的IP地址
 - EMQX_NODE__NAME=emqx@192.168.0.240
 # --- 以下配置在所有节点上必须完全相同 ---
 - EMQX_NODE__COOKIE=YourStrongSecretCookie # 生产环境请使用更复杂的Cookie
 - EMQX_CLUSTER__DISCOVERY_STRATEGY=static
 # 最佳实践:SEEDS 列表包含所有成员,且在所有节点上保持一致
 - EMQX_CLUSTER__STATIC__SEEDS=emqx@192.168.0.240,emqx@192.168.0.188,emqx@192.168.0.189
 volumes:
 - ./data:/opt/emqx/data
 - ./log:/opt/emqx/log

文件 2: 在服务器 B (192.168.0.188) 上创建 docker-compose.yml

version: '3.8'

services:
emqx-node:
 image: emqx/emqx:5.7.2
 container_name: emqx
 restart: always
 network_mode: "host"
 environment:
 # 唯一的不同点:节点名称必须设置为当前主机的IP地址
 - EMQX_NODE__NAME=emqx@192.168.0.188
 # --- 以下配置在所有节点上必须完全相同 ---
 - EMQX_NODE__COOKIE=YourStrongSecretCookie
 - EMQX_CLUSTER__DISCOVERY_STRATEGY=static
 - EMQX_CLUSTER__STATIC__SEEDS=emqx@192.168.0.240,emqx@192.168.0.188,emqx@192.168.0.189
 volumes:
 - ./data:/opt/emqx/data
 - ./log:/opt/emqx/log

文件 3: 在服务器 C (192.168.0.189) 上创建 docker-compose.yml

version: '3.8'

services:
emqx-node:
 image: emqx/emqx:5.7.2
 container_name: emqx
 restart: always
 network_mode: "host"
 environment:
 # 唯一的不同点:节点名称必须设置为当前主机的IP地址
 - EMQX_NODE__NAME=emqx@192.168.0.189
 # --- 以下配置在所有节点上必须完全相同 ---
 - EMQX_NODE__COOKIE=YourStrongSecretCookie
 - EMQX_CLUSTER__DISCOVERY_STRATEGY=static
 - EMQX_CLUSTER__STATIC__SEEDS=emqx@192.168.0.240,emqx@192.168.0.188,emqx@192.168.0.189
 volumes:
 - ./data:/opt/emqx/data
 - ./log:/opt/emqx/log

提示: 服务器 B 和 C 的配置与 A 的配置几乎完全相同,您只需将 EMQX_NODE__NAME 的值修改为各自服务器的 IP 即可。SEEDS 列表在所有节点上都应保持一致,无需更改。

步骤 2: 启动与验证集群

在 所有服务器上分别执行 以下操作:

  1. 准备数据目录

    mkdir -p data log
    sudo chown -R 1000:1000 ./data ./log
    
  2. 启动 EMQX 节点 (建议逐个启动,间隔30秒)

    docker-compose up -d
    
  3. 验证集群状态
    等待约 1 分钟后,在 任意一台服务器 上执行检查命令:

    docker exec emqx-node1 emqx ctl cluster status
    

    您应该能在 Running Nodes 列表中看到所有三个节点的名称。

步骤 3: 扩展现有集群 (添加新节点)

随着业务增长,您可能需要向现有集群中添加新节点。假设我们现在要添加 服务器 D (节点4),其 IP 地址为 192.168.0.190。

  1. 更新所有现有节点的配置
    这是最关键的一步!您必须登录到 服务器 A, B, C,修改各自的 docker-compose.yml 文件,将新节点 emqx@192.168.0.190 添加到 EMQX_CLUSTER__STATIC__SEEDS 列表中。

    例如,服务器 A 的配置应更新为:

      # ... 其他配置 ...
      environment:
        # ... 其他环境变量 ...
        # 将新节点 D 添加到包含所有成员的种子列表
        - EMQX_CLUSTER__STATIC__SEEDS=emqx@192.168.0.240,emqx@192.168.0.188,emqx@192.168.0.189,emqx@192.168.0.190
    
  2. 为新节点创建配置
    在新的 服务器 D (192.168.0.190) 上创建 docker-compose.yml,其 SEEDS 列表应与更新后的其他节点 完全一致。

    # 服务器 D 的配置
    # ...
    environment:
      - EMQX_NODE__NAME=emqx@192.168.0.190
      - EMQX_NODE__COOKIE=YourStrongSecretCookie
      - EMQX_CLUSTER__DISCOVERY_STRATEGY=static
      - EMQX_CLUSTER__STATIC__SEEDS=emqx@192.168.0.240,emqx@192.168.0.188,emqx@192.168.0.189,emqx@192.168.0.190
    # ...
    
  3. 应用变更并启动新节点

    • 在 服务器 A, B, C 上,依次执行以下命令以应用配置变更(滚动更新):
      docker-compose down && docker-compose up -d
      
    • 在新的 服务器 D 上,执行启动命令:
      # 准备目录
      mkdir -p data log && sudo chown -R 1000:1000 ./data ./log
      # 启动
      docker-compose up -d
      
  4. 最终验证
    稍等片刻,在任意节点上再次检查集群状态,您应该能看到全部四个节点都已成功加入。


五、运维与管理:修改配置与数据安全

部署完成后,日常运维是保障系统稳定运行的关键。以下是关于修改配置和数据管理的最常见问题。

1. 修改 docker-compose.yml 文件后如何生效?

答案:必须重启服务容器。

对 docker-compose.yml 的任何修改(例如更改环境变量、更新镜像版本)不会自动应用到正在运行的容器上。您需要按以下步骤操作:

  1. 停止并移除旧容器: 在 docker-compose.yml 所在目录执行:

    docker-compose down
    

    这个命令只会移除容器,并不会删除 Docker 这个软件本身。

  2. 基于新配置创建并启动新容器:

    docker-compose up -d
    

    Docker Compose 会读取您修改后的配置,创建并启动符合新配置的容器。

2. 更新配置会丢失数据吗?—— 持久化的重要性

答案:只要您正确使用了卷(Volumes),数据就不会丢失。

  • 数据安全: 在我们的 docker-compose.yml 示例中,通过 volumes 配置项将容器内的 /opt/emqx/data 和 /opt/emqx/log 目录映射到了宿主机的 ./data 和 ./log 目录。这意味着所有关键数据(如配置、Mnesia 数据库等)都保存在您的服务器硬盘上,而不是临时的容器里。
  • docker-compose down 的行为: 默认情况下,docker-compose down 只会删除容器,它不会触碰您通过 volumes 映射的数据卷。因此,当您用 docker-compose up -d 启动新容器时,它会重新挂载到这些已存在的目录,所有数据都会被完整保留。

⚠️ 高危操作警告

绝对不要随意使用 docker-compose down -v 命令。-v 参数会告诉 Docker Compose 在删除容器的同时,也一并删除关联的数据卷,这将导致您的数据永久丢失!

3. 可以不中断服务,动态热更新吗?

答案:不可以对单个节点热更新,但集群可以实现服务的“滚动更新”。

  • 单个节点: Docker Compose 机制决定了应用新配置必须经过“先销毁,再重建”的过程。因此,被更新的单个节点会有短暂的服务中断。
  • 集群的优势: 这正是集群高可用性的体现!您可以执行 滚动更新 (Rolling Update):逐个更新集群中的节点。例如,先更新节点A,等待其恢复并重新加入集群后,再更新节点B,以此类推。在整个过程中,由于总有其他节点在正常工作,您的整体 MQTT 服务可以保持在线,对客户端的影响降到最低。

六、实战测试:验证集群消息路由

集群搭好了,它真的在协同工作吗?一个简单的“发布/订阅”测试就能证明一切。

  1. 准备工具:下载跨平台的 MQTT 客户端工具 MQTTX。
  2. 创建客户端A:使用 MQTTX 连接到 服务器 A (192.168.0.240:1883),并订阅主题 iot/cluster/test。
  3. 创建客户端B:使用 MQTTX 的新窗口,连接到 服务器 B (192.168.0.188:1883)。
  4. 发布消息:在客户端 B 中,向主题 iot/cluster/test 发布一条消息,例如 Hello, High-Availability EMQX Cluster!。
  5. 见证奇迹:观察客户端 A 的窗口,它应该能立即收到这条消息。

这个测试完美地证明了:消息从一个节点进入,通过集群内部高效路由,成功分发给了连接在另一个节点上的客户端。您的集群正在完美地协同工作。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐