Java 同时从不同应用程序订阅同一主题时未收到MQTT保留消息

Java 同时从不同应用程序订阅同一主题时未收到MQTT保留消息,java,mqtt,paho,hivemq,emq,Java,Mqtt,Paho,Hivemq,Emq,TL;DR 当同时使用多个客户端订阅同一主题树时,并非所有客户端都会收到预期的保留消息 详细信息/用例 在实际项目中,多个应用程序订阅(几乎同时订阅,因为它们是并行启动的)相同的MQTT主题(使用通配符)。该主题包含大约500条保留的消息(每个都在自己的子主题级别),所有应用程序都将收到这些消息(它们使用QoS 1订阅) 除了“配置”消息之外,还使用相同的MQTT连接订阅数据主题。不需要(这里也不需要)持久化状态。因此,应用程序实例连接到cleanSession=true 就我的理解而言,如果应

TL;DR

当同时使用多个客户端订阅同一主题树时,并非所有客户端都会收到预期的保留消息

详细信息/用例

在实际项目中,多个应用程序订阅(几乎同时订阅,因为它们是并行启动的)相同的MQTT主题(使用通配符)。该主题包含大约500条保留的消息(每个都在自己的子主题级别),所有应用程序都将收到这些消息(它们使用QoS 1订阅)

除了“配置”消息之外,还使用相同的MQTT连接订阅数据主题。不需要(这里也不需要)持久化状态。因此,应用程序实例连接到
cleanSession=true

就我的理解而言,如果应用程序实例每个都与一个固定的clientId连接,就足够了,因为cleanSession=true应该避免任何状态处理。但是为了确保没有任何状态被认为是唯一的MQTT clientId,将为每个连接生成

观察到的行为

不幸的是,并非所有应用程序实例都会获得保留的消息。。有些人根本没有收到来自主题的消息——不管订阅持续多长时间。我最初认为maxInflight(客户端)或max_queued_messages(服务器端)配置可能是原因,但在将两者都增加到500000之后,我想这不是失败的原因

复制为测试

因此,我创建了github项目,其中包含一个repo。在repo
MqttSubscriptionTest
中有一个单元测试类,使用测试方法
multi-threadsubscriptiontest
。执行此测试时,一些(1000)保留的消息将首先在
@BeforeClass
方法中发布。之后,将实例化并执行实现
IMqttMessageListener
Runnable
接口的
MqttSubscriber
类的10个实例。每个MqttSubscriber实例将在具有自己的MqttClient实例的自己的线程中执行,并将使用保留的消息订阅主题树。这将记录到控制台,如下所示:

----------- perform subscriptions
Subscriber-3 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-0 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-2 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-4 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-5 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-6 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-1 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-7 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-8 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
Subscriber-9 subscribing topic 'mqtt/client/showcase/mutliThreadSubscription/#'
测试将等待一段时间,然后验证订阅。预计每个订户都会收到1000条保留消息:

----------- validate subscriptions
Subscriber-4: receivedMessages=1000; duration=372ms; succeeded=true
Subscriber-0: receivedMessages=1000; duration=265ms; succeeded=true
Subscriber-5: receivedMessages=1000; duration=475ms; succeeded=true
Subscriber-7: receivedMessages=0; duration=0ms; succeeded=false
Subscriber-6: receivedMessages=1000; duration=473ms; succeeded=true
Subscriber-8: receivedMessages=0; duration=0ms; succeeded=false
Subscriber-9: receivedMessages=1000; duration=346ms; succeeded=true
Subscriber-3: receivedMessages=1000; duration=243ms; succeeded=true
Subscriber-1: receivedMessages=1000; duration=470ms; succeeded=true
Subscriber-2: receivedMessages=1000; duration=357ms; succeeded=true
大多数订户在很短的时间内(大约数百毫秒)收到了预期的1000条消息。但是一些(这里是订户7/8)没有收到一条消息(持续时间为0,因为它们从未完成)。如果给订阅者更多的时间来接收消息,情况并不是更好。他们就是拿不到

我不知道为什么会这样。MQTT代理或客户端上不显示任何错误消息。如果您能提供任何帮助,这对我来说将非常有用,因为我依赖于保留消息的可靠传递

在GitHub上复制

  • 我使用本地EMQ和HiveMQ代理进行了测试。如果要运行测试,需要在本地主机:1883的计算机上运行代理,或者更改测试类中的配置
  • 我使用EclipsePAHOJava客户机MQTT
  • 我订阅了
    cleanSession=true
    ,因为我不想有任何状态(连接用于订阅多个主题,不希望传递错过的消息)

在连接过程中,您不能使用
cleanSession(true)
,请参阅此处的说明:

我使用蚊子进行测试,默认情况下它的内部消息队列只有100个

HiveMQ具有最大队列消息数

Emq-config也有类似的功能

我修复了repo中的示例代码。对我有用

编辑:刚刚用Emq测试过它(
docker run--rm-ti--name Emq-p 18083:18083-p 1883:1883-qoodt/Emq docker:latest
),它工作正常

基本上,这是错误的:必须是错误的。
除此之外,测试代码中的等待状态很糟糕。它们在我的机器上太短了。使用闩锁或其他真正的同步机制。

在连接期间,您不能使用
cleanSession(true)
,请参阅此处的说明:

我使用蚊子进行测试,默认情况下它的内部消息队列只有100个

HiveMQ具有最大队列消息数

Emq-config也有类似的功能

我修复了repo中的示例代码。对我有用

编辑:刚刚用Emq测试过它(
docker run--rm-ti--name Emq-p 18083:18083-p 1883:1883-qoodt/Emq docker:latest
),它工作正常

基本上,这是错误的:必须是错误的。
除此之外,测试代码中的等待状态很糟糕。它们在我的机器上太短了。使用闩锁或其他真正的同步机制。

HiveMQ人员非常友好地研究了这个问题。他们怀疑原因在于Paho客户端和订阅中使用的
imqttmMessageListener
。有一个关于假定种族条件的问题


经验教训:更好地使用
MqttCallback
而不是
IMqttMessageListener

HiveMQ人员非常友好地研究了这个问题。他们怀疑原因在于Paho客户端和订阅中使用的
imqttmMessageListener
。有一个关于假定种族条件的问题


经验教训:最好使用
MqttCallback
而不是
IMqttMessageListener

您已经用两个不同的代理(emq和hivemq)对此进行了标记,但实际上并没有说您是哪一个using@hardillb正确的。很抱歉我尝试了两个经纪人,问题都发生在他们身上。也许这是Eclipse paho java MQTT客户机的问题(?)。或者是配置问题。您已经用两个不同的代理(emq和hivemq)标记了它,但没有实际说明您是哪一个using@hardillb正确的。很抱歉