EMQX的docker部署与使用(mqtt)

1:先创建一个挂载emqx的目录

2:docker拉去emqx

docker pull emqx/emqx:latest

2-1:先启动一次eqmx,然后停止,删除容器

docker run -d --name emqx --privileged=true -p 1883:1883 -p 8883:8883 -p 8083:8083 -p 8084:8084 -p 8081:8081 -p 18083:18083  emqx/emqx:latest

以下是每一个端口对应的作用和协议,需要用上那个,就可以开启那个

2025-01-01 09:32:24 WARNING: NOTE: Use the same cookie for all nodes in the cluster.
2025-01-01 09:32:25 EMQX_RPC__PORT_DISCOVERY [rpc.port_discovery]: manual
2025-01-01 09:32:25 EMQX_NODE__NAME [node.name]: emqx@172.17.0.2
2025-01-01 09:32:27 Listener ssl:default on 0.0.0.0:8883 started.
2025-01-01 09:32:27 Listener tcp:default on 0.0.0.0:1883 started.
2025-01-01 09:32:27 Listener ws:default on 0.0.0.0:8083 started.
2025-01-01 09:32:27 Listener wss:default on 0.0.0.0:8084 started.
2025-01-01 09:32:27 Listener http:dashboard on :18083 started.
2025-01-01 09:32:27 EMQX 5.2.0-build.1 is running now!

2-2:然后复制eqmx目录

docker cp emqx:/opt/emqx .
  • 这个命令是使用 Docker 的 docker cp 命令来从一个正在运行的容器中将文件或目录复制到主机上
  • 这里是引用
  • 具体解释如下:
  • docker cp:Docker 命令,用于在容器和主机之间复制文件或目录。
  • emqx:容器名称或容器 ID,指定要复制文件或目录的容器。
  • /opt/emqx:容器内的路径,指定要复制的文件或目录在容器内的位置。
  • . 主机内的路径,指定要将文件或目录复制到主机上的位置。. 表示当前用户的主目录。
  • 综合起来,命令 docker cp emqx:/opt/emqx ~ 表示将容器 emqx 中位于 /opt/emqx 路径下的文件或目录复制到当前用户的主目录下。这可以将容器内的文件或目录复制到主机上进行查看、编辑或处理。

2-3:然后停止,删除容器

docker stop emqx
docker rm emqx

2-4:再重新启动容器与挂载

docker run -d --name emqx --privileged=true -p 1883:1883 -p 8883:8883 -p 8083:8083 -p 8084:8084 -p 8081:8081 -p 18083:18083 -v /root/emqx:/opt/emqx emqx/emqx:latest

3:登录EMQX的dashboard界面:输入http://127.0.0.1:18083,默认账号:admin,密码:public

在这里插入图片描述

3-1:EMQX的网页客户端工具http://www.emqx.io/online-mqtt-client

在这里插入图片描述

3-2:添加客户端连接EMQX的认证方式(账号或者客户id,默认是随意账号或者客户id都可以连接)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3-3:输入账号密码保存后,客户端连接就需要使用存在的账号和密码才能连接

在这里插入图片描述

3-4:客户端连接就需要使用存在的账号和密码才能连接

在这里插入图片描述

4:桥接模式,可以转发主题的内容到http或者mqtt,如下转发http配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4-1:使用客户发送消息

在这里插入图片描述

4-2:http服务的服务端与接收到的数据

在这里插入图片描述

4-2:http服务的只接受mqtt内容发的信息,不需要额外信息,设置payload,修改如下

在这里插入图片描述

5:EMQX问题分析在这里插入图片描述

6:Java代码的引入使用,pom导入依赖

<dependencies>
   <dependency>
       <groupId>org.eclipse.paho</groupId>
       <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
       <version>1.2.5</version>
   </dependency>
</dependencies>

6-1:然后创建 MQTT 客户端并连接

MqttClient client = new MqttClient(broker, clientid, new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
client.connect(options);
  • MqttClient: 同步调用客户端,使用阻塞方法通信
  • MqttClientPersistence: 代表一个持久的数据存储,用于在传输过程中存储出站和入站的信息,使其能够传递到指定的 QoS
  • MqttConnectOptions: 连接选项,用于指定连接的参数,下面列举一些常见的方法
  • setUserName: 设置用户名
  • setPassword: 设置密码
  • setCleanSession: 设置是否清除会话
  • setKeepAliveInterval: 设置心跳间隔
  • setConnectionTimeout: 设置连接超时时间
  • setAutomaticReconnect: 设置是否自动重连

6-2:发布 MQTT 消息(tcp://协议前缀即使工具的mqtt://协议)

package io.emqx.mqtt;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class PublishSample {

   public static void main(String[] args) {

       String broker = "tcp://192.168.11.50:1883";
       //String broker = "ws://192.168.11.50:8083/mqtt";//看emqt开启了什么服务
       String topic = "mqtt/test";
       String username = "emqx";
       String password = "public";
       String clientid = "publish_client";
       String content = "Hello MQTT";
       int qos = 0;

       try {
           MqttClient client = new MqttClient(broker, clientid, new MemoryPersistence());
           // 连接参数
           MqttConnectOptions options = new MqttConnectOptions();
           // 设置用户名和密码
           options.setUserName(username);
           options.setPassword(password.toCharArray());
           options.setConnectionTimeout(60);
      options.setKeepAliveInterval(60);
           // 连接
           client.connect(options);
           // 创建消息并设置 QoS
           MqttMessage message = new MqttMessage(content.getBytes());
           message.setQos(qos);
           // 发布消息
           client.publish(topic, message);
           System.out.println("Message published");
           System.out.println("topic: " + topic);
           System.out.println("message content: " + content);
           // 关闭连接
           client.disconnect();
           // 关闭客户端
           client.close();
      } catch (MqttException e) {
           throw new RuntimeException(e);
      }
  }
}

6-3:订阅 MQTT 主题

package io.emqx.mqtt;

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class SubscribeSample {
   public static void main(String[] args) {
       String broker = "tcp://broker.emqx.io:1883";
       String topic = "mqtt/test";
       String username = "emqx";
       String password = "public";
       String clientid = "subscribe_client";
       int qos = 0;

       try {
           MqttClient client = new MqttClient(broker, clientid, new MemoryPersistence());
           // 连接参数
           MqttConnectOptions options = new MqttConnectOptions();
           options.setUserName(username);
           options.setPassword(password.toCharArray());
           options.setConnectionTimeout(60);
      options.setKeepAliveInterval(60);
           // 设置回调
           client.setCallback(new MqttCallback() {

               public void connectionLost(Throwable cause) {
                   System.out.println("connectionLost: " + cause.getMessage());
              }

               public void messageArrived(String topic, MqttMessage message) {
                   System.out.println("topic: " + topic);
                   System.out.println("Qos: " + message.getQos());
                   System.out.println("message content: " + new String(message.getPayload()));

              }

               public void deliveryComplete(IMqttDeliveryToken token) {
                   System.out.println("deliveryComplete---------" + token.isComplete());
              }

          });
           client.connect(options);
           client.subscribe(topic, qos);
      } catch (Exception e) {
           e.printStackTrace();
      }
  }
}

  • MqttCallback 说明:
  • connectionLost(Throwable cause): 连接丢失时被调用
  • messageArrived(String topic, MqttMessage message): 接收到消息时被调用
  • deliveryComplete(IMqttDeliveryToken token): 消息发送完成时被调用

6-4:MqttCallback单独做一个接口修改如下

package com.example.poi.utils;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 * @Author xu
 * @create 2023/9/14 11
 */
public class SampleCallback implements MqttCallback {
    public void connectionLost(Throwable cause) {
        System.out.println("connection lost:" + cause.getMessage());
    }

    public void messageArrived(String topic, MqttMessage message) {
        System.out.println("Received message: \n  topic:" + topic + "\n  Qos:" + message.getQos() + "\n  payload:" + new String(message.getPayload()));
    }

    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("deliveryComplete");
    }
}

6-5:mqtt回调就可以是使用如下方式

client.setCallback(new SampleCallback());

7:emqx通讯,如果消费端断开了一天,但是发送端一直发送消息到emqx,怎么保证当消费端正常后,可以消费断开期间的全部消息

  • EMQ X 是支持 MQTT 消息队列功能的消息中间件,因此可以通过 EMQ X 实现在消费端断开期间保留消息,并在消费端重新连接后将离线期间的消息推送给消费端。
    具体实现方法如下:

7-1:在消费端连接 EMQ X 时,设置 clean_session 参数为 false,这样消费端和 EMQ X 之间的连接不会在消费端断开时自动清除

MqttClient client = new MqttClient(broker, clientId, new MemoryPersistence());
// 连接参数
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setConnectionTimeout(60);
options.setKeepAliveInterval(60);
/**消费端和 EMQ X 之间的连接不会在消费端断开时自动清除,当断开后,只要会话过期时间到了,才会消失,可以保证只要有会话在,连上后就可以消费断开之间的消息,如果不想消费断开之间的消息就重新生成一个客户端id,即可解决问题*/
options.setCleanSession(false);
  • 注意EQMX的开启cleanSession会话为false的时候,默认的会话过期时间为2小时,可以通过修改EMQX配置目录opt/emqx/emqx.conf里添加会话过期时间,单位为毫秒,如下设置为1个小时

mqtt.session_expiry_interval =3600000

7-2:订阅主题时,使用 QoS 级别为 1 或 2,这样如果发送端在消费端断开期间发布消息,它们将被存储在 EMQ X 中

7-3:在 EMQ X 中,开启 Retained Message 功能,可以确保消费端在订阅时能够接收到最新的消息,而不是在消费端重新连接后接收到旧的消息

String content="阳光明媚";
MqttMessage message = new MqttMessage(content.getBytes());
message. setQos(qos);
/**保留消息,最新一条记录一定可以被消费,只要有客户端连接都可以消费到最新的消息*/
message.setRetained(true);
client.publish(topic, message);
  • 如果发送方发送了很多消息,但消费端断开时间很长,可能会导致 EMQ X 中消息数量过多,建议在 EMQ X 中设置合适的消息过期时间或清理策略,以确保系统性能

8:客户端断开怎么设置自动重连, options.setAutomaticReconnect(true)

  • 在设置 options.setAutomaticReconnect(true) 之前,已经调用了 options.setCleanSession(true) 方法,并且客户端与代理断开连接时,代理会清除客户端的会话信息。在这种情况下,自动重新连接可能无法生效
  • 要解决这个问题,可以尝试将 options.setCleanSession(true) 改为 options.setCleanSession(false),以保留客户端的会话信息,从而使得自动重新连接有效
options.setCleanSession(false);
options.setAutomaticReconnect(true);
  • 回调类修改,可以观察重连状态
package com.example.poi.utils;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 * @Author xu
 * @create 2023/9/14 11
 */
public class SampleCallback implements MqttCallbackExtended {

    public void connectionLost(Throwable cause) {
        System.out.println("connection lost:" + cause.getMessage());
    }

    public void messageArrived(String topic, MqttMessage message) {
        System.out.println("Received message: \n  topic:" + topic + "\n  Qos:" + message.getQos() + "\n  payload:" + new String(message.getPayload()));
    }

    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("deliveryComplete");
    }


    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        System.out.println(serverURI);
        System.out.println(reconnect);
    }
}

9:使用ws(默认端口8083)协议发布消息到MQTT,使用ws协议的好处就是后缀有必须的路径/mqtt,方便好处就是可以在nginx代理的时候进行路径转发,这是订阅端代码,发布端代码,使用mqtt(tcp)协议,ws协议都是一样,其实只要修改发布端的url为ws的路径即可以,其他代码都不需要修改

import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

public class MqttSubscriber {

    public static void main(String[] args) {
        // 替换为你的 MQTT 代理的 WebSocket 端点 URL
        String brokerUrl = "ws://192.168.11.50:8083/mqtt";
        String clientId = "JavaClient";
        String topic = "realtime";

        try {
            // 创建一个 MQTT 客户端
            MqttAsyncClient client = new MqttAsyncClient(brokerUrl, clientId);
            MqttConnectOptions options = new MqttConnectOptions();
            options.setAutomaticReconnect(true);
            options.setCleanSession(true);
            options.setConnectionTimeout(10);

            // 连接到 MQTT 代理
            System.out.println("Connecting to broker: " + brokerUrl);
            client.connect(options).waitForCompletion();
          
            // 订阅主题
            System.out.println("Subscribing to topic: " + topic);
            client.subscribe(topic, 1);

            // 为订阅设置回调,以便在收到消息时执行操作
            client.setCallback(new org.eclipse.paho.client.mqttv3.MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    System.out.println("Connection to MQTT broker lost!");
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    System.out.println("Message arrived. Topic: " + topic + " Message: " + new String(message.getPayload()));
                }

                @Override
                public void deliveryComplete(IMqttToken token) {
                    System.out.println("Delivery is complete!");
                }
            });

            // 保持程序运行,以便接收消息
            Thread.sleep(Long.MAX_VALUE);

        } catch (MqttException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
<think>好的,我现在需要帮助用户找到如何使用Docker搭建EMQX集群的教程或指南。首先,我得回忆一下EMQX的相关知识。EMQX是一个开源的MQTT代理,常用于物联网消息传递。用户提到他们遇到了“OS monotonic time stepped backwards”的错误,并且引用中提到了使用Docker部署时的问题,还有建议在vm.args中添加'+c false'。这可能时间同步或容器配置有关,但用户现在的主要需求是集群的搭建方法。 首先,我需要整理Docker部署EMQX集群的基本步骤。通常,Docker集群部署涉及创建多个容器,并确保它们能够互相发现和通信。EMQX集群通常使用手动或自动的方式。手动方式需要设置每个节点的名称,并让它们加入到一个主节点。自动方式可能使用DNS或Kubernetes的服务发现,但用户可能是在简单的Docker环境下,所以手动方式更可能。 接下来,我需要考虑网络配置。Docker容器之间的通信需要同一网络,所以用户需要创建一个Docker网络,然后将所有EMQX容器连接到这个网络。这样,容器可以通过容器名称或别名相互访问。 然后,配置每个EMQX节点的名称。EMQX节点名称通常采用格式emqx@<hostname>,所以在Docker中,hostname可能需要设置为容器名或自定义的名称。例如,使用--name参数指定容器名,然后在启动命令中设置节点名称。 用户提供的引用中提到使用emqx_ctl cluster status命令检查集群状态,这应该在每个容器内执行。此外,用户遇到的错误可能需要调整Erlang虚拟机的参数,比如在vm.args中添加+c false,这可能时间源有关,需要确保容器的时间同步正确。 现在,我需要把这些步骤具体化,写出一个配置示例,包括Docker命令和必要的参数。例如,创建网络,启动两个节点,并让第二个节点加入第一个节点。同时,需要处理可能的错误,如引用中的错误,可能需要添加环境变量或修改配置文件。 最后,生成相关问题,可能涉及集群管理、故障排除、性能优化等。例如,如何检查集群状态,如何处理节点加入失败,如何优化集群性能等。 在整理过程中,要确保所有数学表达式和代码块符合格式要求,使用中文回答,并正确引用提供的参考资料。特别是引用[1]中的检查集群状态的命令,引用[2]和[3]中的错误处理建议。</think>### 使用Docker部署EMQX集群的方法 #### 1. 创建Docker专用网络 ```bash docker network create emqx-net ``` 容器间通信需要共享同一网络环境,专用网络能确保节点通过容器名称直接互通[^1]。 #### 2. 启动第一个节点 ```bash docker run -d \ --name emqx1 \ --network emqx-net \ -p 1883:1883 -p 8083:8083 -p 8084:8084 \ -e EMQX_NODE_NAME=emqx@node1.emqx.local \ -e EMQX_CLUSTER__DISCOVERY=manual \ emqx/emqx:5.8.0 ``` * `EMQX_NODE_NAME` 设置节点唯一标识 * `-p` 参数映射MQTT/WebSocket端口 * `manual` 表示手动组网模式 #### 3. 启动第二个节点并加入集群 ```bash docker run -d \ --name emqx2 \ --network emqx-net \ -e EMQX_NODE_NAME=emqx@node2.emqx.local \ -e EMQX_CLUSTER__DISCOVERY=manual \ -e EMQX_CLUSTER__STATIC__SEEDS="emqx@node1.emqx.local" \ emqx/emqx:5.8.0 ``` 通过`CLUSTER__STATIC__SEEDS`指定种子节点实现自动加入集群。 #### 4. 验证集群状态 ```bash docker exec emqx1 emqx_ctl cluster status ``` 输出应显示两个节点的`running`状态。 ### 配置示例说明 ```docker-compose.yml version: '3' services: emqx1: image: emqx/emqx:5.8.0 networks: - emqx-net environment: EMQX_NODE_NAME: "emqx@node1.emqx.local" EMQX_CLUSTER__DISCOVERY: manual ports: - "1883:1883" - "8083:8083" emqx2: image: emqx/emqx:5.8.0 networks: - emqx-net environment: EMQX_NODE_NAME: "emqx@node2.emqx.local" EMQX_CLUSTER__DISCOVERY: manual EMQX_CLUSTER__STATIC__SEEDS: "emqx@node1.emqx.local" networks: emqx-net: driver: bridge ``` ### 常见问题处理 若出现时间同步错误`OS monotonic time stepped backwards`,可在环境变量中添加: ```bash -e EMQX_VM_ARGS="+c false" ``` 该配置禁用时间一致性检查,适用于虚拟机环境[^3]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值