HiveMQ与持久会话共享订阅

时间:2017-02-14 16:18:54

标签: hivemq

尝试结合HiveMQ的两个功能:共享订阅和持久会话。

如果创建了一个非常简单的消息生产者。一个非常简单的消费者。 当运行多个消费者时,所有消费者都会收到所有消息。

在为消费者设置clearSession为'false'之后,当运行使用者并重新启动使用者时,使用者也会在未连接时收到消息。优异。

现在将其与共享订阅功能相结合。 仅使用共享订阅时,clearSession为“true”。运行多个使用者时,只有单个使用者才能收到消息。它应该是循环的,情况也是如此,但是一旦你停止消费者,消息就不再循环,但其中一个消费者得到的消息明显多于其他消息。

如果我现在再次启用持久会话,则clearSession为'false',并启动共享订阅消费者,消费者再次开始接收所有消息,而不是仅将消息传递给一个客户端。

这是什么问题? 这是HiveMQ中的错误吗? 持久会话和共享订阅是否可以一起使用?那真是太无聊了。

更新15/2/2017 正如@fraschbi建议我清除所有数据并再次使用持久会话消费者重新测试共享订阅。它似乎工作!

但奇怪的是,只有在第一个消费者重新连接后才会收到错过的消息。 所有消费者都有相同的代码,他们只是从不同的clientId参数开始。见下面的代码。 我的测试顺序:

  • 启动了consumer1:所有消息都是这个消费者。
  • 启动consumer2:每个消费者都收到所有其他消息。
  • 启动了consumer3:每个消费者获得三分之一的消息。
  • 停止使用consumer1:现在,consumer2和3接收所有其他消息。 (不知道为什么我昨天看到这种不均匀的分布,但也许正如@fraschbi所提到的那样,因为我正在重复使用clientId并没有取消订阅或正确断开连接)
  • 现在停止使用consumer2:consumer3现在收到所有消息。
  • 停止使用者3:不再收到任何消息。
  • 重新启动consumer3:它继续生成器发送的第一条消息。 它不会收到丢失的消息
  • 重新启动consumer2:消息再次均匀分布。
  • 重启consumer1:这一个现在收到所有丢失的消息,然后继续接收每三个消息中的1/3。

所以我的新问题是:为什么只有第一位消费者收到丢失的消息?

注意:停止客户端时,这里仍然没有取消订阅,因为订阅/持久性设置丢失了!

Producer.scala

object Producer extends App {

  val topic = args(0)
  val brokerUrl = "tcp://localhost:1883"

  val clientId = UUID.randomUUID().toString

  val client = new MqttClient(brokerUrl, clientId)
  client.connect()
  val theTopic = client.getTopic(topic)

  var count = 0

  sys.addShutdownHook {
    println("Disconnecting client...")
    client.disconnect()
    println("Disconnected.")
  }

  while(true) {
    val msg = new MqttMessage(s"Message: $count".getBytes())
    theTopic.publish(msg)
    println(s"Published: $msg")

    Thread.sleep(1000)

    count = count + 1
  }
}

Consumer.scala

object Consumer extends App {

  val topic = args(0)
  val brokerUrl = "tcp://localhost:1883"

  val clientId = args(1)
//  val clientId = UUID.randomUUID().toString

  val client = new MqttClient(brokerUrl, clientId)
  client.setCallback(new MqttCallback {
    override def deliveryComplete(token: IMqttDeliveryToken) = ()

    override def messageArrived(topic: String, message: MqttMessage) = println(s"received on topic '$topic': ${new String(message.getPayload)}")

    override def connectionLost(cause: Throwable) = println("Connection lost")
  })

  println(s"Start $clientId consuming from topic: $topic")
  val options = new MqttConnectOptions()
  options.setCleanSession(false);

  client.connect(options)
  client.subscribe(topic)

  sys.addShutdownHook {
    println("Disconnecting client...")
//    client.unsubscribe(topic)
    client.disconnect()
    println("Disconnected.")
  }


  while(true) {

  }

}

1 个答案:

答案 0 :(得分:3)

我将尝试单独回答您遇到的两个问题。

  

它应该是循环的,情况也是如此,但是一旦你停止消费者,消息就不再循环,但其中一个消费者得到的消息明显多于其他消息。

在为共享订阅分发邮件时,HiveMQ确实更喜欢在线客户端。

  

如果我现在再次启用持久会话,则clearSession为' false'并启动共享订阅消费者,消费者开始再次接收所有消息,而不是仅将消息传递给一个客户端。

在问题的开头,您说您正在将cleanSession=false的客户端连接到代理并订阅该主题。 (听起来好像你只使用一个主题。) 是否可以在重新连接cleanSession=false和共享订阅之前取消订阅这些客户端?在这种情况下,您的方案的第一步中的订阅仍将保留给那些客户端,并且他们自然会收到消息。

编辑:

  

所以我的新问题是:为什么只有第一个消费者收到丢失的消息?

来自HiveMQ用户指南:

  

当客户端脱机队列已满时,不会删除该客户端的邮件,而是排队等待共享订阅组中的下一个脱机客户端。

当所有客户端都处于脱机状态时,分发不再是循环播放。因此,您描述的方案符合预期的行为。

消息队列的默认值为1000.因此,您可以发送超过1000条消息,同时客户端处于脱机状态,或者减少消息队列大小。

...
<persistence>
     <queued-messages>

         <max-queued-messages>50</max-queued-messages>

     </queued-messages>
    ...
</persistence>
...

将此添加到config.xml以减少邮件队列大小。