开源版 EMQX(集群版)搭建

前面介绍了开源版 EMQX 单机版搭建、客户端认证配置、SpringBoot 程序访问,本篇博客承接之前的博客内容。

开源版 EMQX 集群节点梳理有限制,最多支持 3 个节点(无主集群),最多支持 10 万个连接,绝大多数情况下已经够用了。

本篇博客使用开源版 EMQX 搭建 3 个节点的集群,使用 nginx 转发 tcp 端口、WebSocket 端口、Web 后台管理工具端口,使用 mysql 进行存储客户端连接账号。

开源版 EMQX 功能官网文档:https://docs.emqx.com/zh/emqx/v5.8/getting-started/feature-comparison.html

EMQX 集群搭建官网文档:https://docs.emqx.com/zh/emqx/v5.8/deploy/cluster/create-cluster.html


一、集群搭建

我使用虚拟机(IP 地址是 192.168.136.128)采用 docker-compose 搭建一个 3 节点的伪集群。

首先创建一个 emqx_cluster 文件夹,在内部创建 3 个节点目录和 1 个 nginx 目录。

每个节点目录下包含 data 和 log 目录,为了确保数据写入权限,将 data 和 log 目录的权限都设置成了 777。

nginx 目录下主要是 nginx.conf 配置文件。 emqx_cluster 文件夹下详细结构如下:

01

编写 docker-compose.yml 文件内容如下:

services:
  emqx1:
    # 使用开源版镜像的最新版本
    image: emqx/emqx:5.8.9
    # 容器服务名称
    container_name: emqx1
    # 这个很重要,数据存储目录需要使用主机名
    # 如果主机名发生变化,数据目录下会创建一个新的目录存放数据
    hostname: node1.jobs.com
    privileged: true
    restart: always
    volumes:
      # 数据目录
      - ./emqx1/data:/opt/emqx/data:rw
      # 日志目录
      - ./emqx1/log:/opt/emqx/log:rw
      # 使容器内的时间相关设置与宿主机保持一致
      - /etc/localtime:/etc/localtime
    environment:
      # 跟上面 hostname 配置保持一致
      - EMQX_HOST=node1.jobs.com
      # 节点名称
      - EMQX_NODE__NAME=emqx@node1.jobs.com
      # cookie名称(各节点的cookie值必须一致)
      - EMQX_NODE__COOKIE=jobscookie
      # 集群名称(各节点的集群名称必须一致)
      - EMQX_CLUSTER__NAME=jobscluster
      # 手动配置集群
      - EMQX_CLUSTER__DISCOVERY_STRATEGY=manual
      # 启用文件日志
      - EMQX_LOG__FILE__DEFAULT__ENABLE=true
      # 关闭控制台日志
      - EMQX_LOG__CONSOLE__ENABLE=false
      # 禁用遥测(遥测是官方对用户收集系统使用相关信息,开源版特有的功能,建议禁用)
      - EMQX_TELEMETRY__ENABLE=false
      # 设置中国时区
      - TZ=Asia/Shanghai
      # 自定义配置 tcp 端口
      #- EMQX_LISTENERS__TCP__DEFAULT__BIND=1883
      # 自定义配置加密安全的 tcp 端口
      #- EMQX_LISTENERS__SSL__DEFAULT__BIND=8883
      # 自定义配置 WebSocket 的端口
      #- EMQX_LISTENERS__WS__DEFAULT__BIND=8083
      # 自定义配置加密安全的 WebSocket 的端口
      #- EMQX_LISTENERS__WSS__DEFAULT__BIND=8084
      # 自定义配置Web后台工具的访问端口
      #- EMQX_DASHBOARD__LISTENERS__HTTP__BIND=18083
    networks:
      - emqx_clsuter_net

  emqx2:
    image: emqx/emqx:5.8.9
    container_name: emqx2
    hostname: node2.jobs.com
    privileged: true
    restart: always
    volumes:
      - ./emqx2/data:/opt/emqx/data:rw
      - ./emqx2/log:/opt/emqx/log:rw
      - /etc/localtime:/etc/localtime
    environment:
      - EMQX_HOST=node2.jobs.com
      - EMQX_NODE__NAME=emqx@node2.jobs.com
      - EMQX_NODE__COOKIE=jobscookie
      - EMQX_CLUSTER__NAME=jobscluster
      - EMQX_CLUSTER__DISCOVERY_STRATEGY=manual
      - EMQX_LOG__FILE__DEFAULT__ENABLE=true
      - EMQX_LOG__CONSOLE__ENABLE=false
      - EMQX_TELEMETRY__ENABLE=false
      - TZ=Asia/Shanghai
    networks:
      - emqx_clsuter_net

  emqx3:
    image: emqx/emqx:5.8.9
    container_name: emqx3
    hostname: node3.jobs.com
    privileged: true
    restart: always
    volumes:
      - ./emqx3/data:/opt/emqx/data:rw
      - ./emqx3/log:/opt/emqx/log:rw
      - /etc/localtime:/etc/localtime
    environment:
      - EMQX_HOST=node3.jobs.com
      - EMQX_NODE__NAME=emqx@node3.jobs.com
      - EMQX_NODE__COOKIE=jobscookie
      - EMQX_CLUSTER__NAME=jobscluster
      - EMQX_CLUSTER__DISCOVERY_STRATEGY=manual
      - EMQX_LOG__FILE__DEFAULT__ENABLE=true
      - EMQX_LOG__CONSOLE__ENABLE=false
      - EMQX_TELEMETRY__ENABLE=false
      - TZ=Asia/Shanghai
    networks:
      - emqx_clsuter_net

  nginx:
    image: nginx
    container_name: nginx
    privileged: true
    restart: always
    ports:
      # web管理界面访问
      - "18083:18083"
      # 程序访问端口
      - "1883:1883"
      # WebSocket访问端口
      - "8083:8083"
    volumes:
      # 配置文件映射
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      # 静态页面目录映射
      - ./nginx/html:/usr/share/nginx/html
      - /etc/localtime:/etc/localtime
    networks:
      - emqx_clsuter_net

networks:
  emqx_clsuter_net:
    driver: bridge

需要注意的是:3 个节点的集群名称必须一致,cookie 名称也必须一致。上面的 yml 文件相关的环境变量配置说明已经很详细。

这里就不映射 3 个节点容器内部的 tcp 端口、websocket 端口和 web 后台工具端口到宿主机了,我们通过 nginx 将这些端口转发即可,nginx.conf 内容如下:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections 10240;
}

http {
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    client_max_body_size 100m;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    # 代理 emqx 集群的 web 后台管理工具端口
    upstream emqx_web {

        # max_fails:允许请求失败的次数;默认为 1
        # fail_timeout:失败超时时间,默认 10s, max_fails 达到次数后暂停的请求时间

        # 使用服务名代替ip地址,采用轮询的负载均衡方式
        server emqx1:18083 max_fails=2 fail_timeout=5s;
        server emqx2:18083 max_fails=2 fail_timeout=5s;
        server emqx3:18083 max_fails=2 fail_timeout=5s;
    }

    server {
        listen 18083;
        server_name jobsweb.cluster.com;

        location / {

            proxy_pass http://emqx_web;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";

            # 禁用缓存
            proxy_buffering off;

            # 反向代理真实 IP
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    # 代理 emqx 集群的 websocket 端口
    upstream emqx_websocket {

        # max_fails:允许请求失败的次数;默认为 1
        # fail_timeout:失败超时时间,默认 10s, max_fails 达到次数后暂停的请求时间

        # 使用服务名代替ip地址,采用轮询的负载均衡方式
        server emqx1:8083 max_fails=2 fail_timeout=5s;
        server emqx2:8083 max_fails=2 fail_timeout=5s;
        server emqx3:8083 max_fails=2 fail_timeout=5s;
    }

    server {
        listen 8083;
        server_name jobsws.cluster.com;

        location /mqtt {

            proxy_pass http://emqx_websocket;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";

            # 禁用缓存
            proxy_buffering off;

            proxy_connect_timeout 10s;        
            # WebSocket 连接有效时间
            # 在该时间内没有数据交互的话 WebSocket 连接会自动断开,默认为 60s 
            proxy_send_timeout 3600s;
            proxy_read_timeout 3600s;

            # 反向代理真实 IP
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    include /etc/nginx/conf.d/*.conf;
}

stream {

    # 代理 emqx 集群的 tcp 端口
    upstream emqx_tcp {

        # max_fails:允许请求失败的次数;默认为 1
        # fail_timeout:失败超时时间,默认 10s, max_fails 达到次数后暂停的请求时间

        # 使用服务名代替ip地址,采用轮询的负载均衡方式
        server emqx1:1883 max_fails=2 fail_timeout=5s;
        server emqx2:1883 max_fails=2 fail_timeout=5s;
        server emqx3:1883 max_fails=2 fail_timeout=5s;
    }

    server {
        listen 1883;
        proxy_pass emqx_tcp;

        # 不延迟响应
        tcp_nodelay on;
    }
}

在 docker-compose.yml 文件所在目录,运行 docker-compose up -d 启动服务。

注意:此时只是启动了 3 个节点,还没有组成集群,此时通过 nginx 访问 Web 后台工具,能登录成功,但是无法修改密码。

由于 EMQX 搭建的是无主集群,我们采用手动方式搭建集群(这样比较灵活),因此使用任意两个节点,加入另外一个节点即可实现集群的搭建。

我们就在 emqx2 和 emqx3 容器内运行命令,让这两个节点加入到 emqx1 即可,运行以下两条命令:

# 进入 emqx2 容器执行命令,让 emqx2 加入到 emqx1
docker exec -it emqx2 ./bin/emqx_ctl cluster join emqx@node1.jobs.com
# 进入 emqx3 容器执行命令,让 emqx3 加入到 emqx1
docker exec -it emqx3 ./bin/emqx_ctl cluster join emqx@node1.jobs.com

02

运行以上 2 个命令,能够看到成功的提示,集群就搭建成功了。下面再列出常用的集群管理命令:

# 可以在任意集群节点 docker 容器中运行命令,查看集群状态。比如我们在 emqx1 容器内运行命令:
docker exec -it emqx1 ./bin/emqx_ctl cluster status

# 如果哪个节点想要退出集群,也可以运行命令退出。比如我们 emqx3 容器的服务退出集群:
# 哪个节点想要退出集群,就在哪个容器内部执行该命令
docker exec -it emqx3 ./bin/emqx_ctl cluster leave

# 如果想要把其它节点从集群中移除掉,可以运行以下命令。比如我们在 emqx1 容器内部执行命令,把 emqx2 节点从集群中移除:
docker exec -it emqx1 ./bin/emqx_ctl force-leave emqx2

二、界面展示

我们可以访问 nginx 的 18083 端口(http://192.168.136.128:18083)能够看到 Web 后台工具的登录页面。

输入用户名 admin 和密码 public 登录成功,然后按照界面提示修改 admin 密码后,即可进入 Web 后台工具首页,在【集群概览】的【节点】选项卡查看集群搭建情况。

我使用之前博客搭建的 web 版 MQTT 工具采用 WebSocket 连接 nginx 的 8083 端口,使用桌面版 MQTT 工具连接 nginx 的 1883 端口,都可以连接成功。

03

在【客户端】页面可以看到 2 个客户端的连接情况。

04

默认情况下,任何客户端工具都可以通过 nginx 连接到 EMQX 集群中,我们可以在【访问控制】下的【客户端认证】页面,创建基于 mysql 的账号密码访问控制,防止客户端匿名连接,保障访问的安全性。

可以参考之前发布的博客:开源版 EMQX(单机版)搭建和客户端认证配置

05

经过实际测试,两个客户端之间互相向对方订阅的主题发送消息,能够成功接收到对方发来的消息。这里就不截图演示了。

上篇博客提供了 Springboot 程序示例代码,想要连接集群收发消息的话,只需要在 yml 配置文件中的地址、账号、密码修改为集群相应参数即可。

posted @ 2026-02-19 22:55  乔京飞  阅读(5200)  评论(0)    收藏  举报