【问题标题】:inconsistent persistence in mosquitto蚊子的持久性不一致
【发布时间】:2020-10-28 15:38:10
【问题描述】:

我在 mosquitto 上看到消息持久性和 qos=2 的消息传递不一致。是不是我做错了什么?

我有一个简单的测试应用程序,它使用 clientId="receive-client" 注册消费主题,但立即断开连接。然后它以 clientId="send-client" 的身份连接并发布 10 条消息,“message #1”...“message #10”。然后断开连接,等待 5 秒,然后在打印和计算收到的消息时再次连接以使用“receive-client”消费。

结果不一致。有时我收到 6 条消息,有时是 8 条。典型的输出是这样的:

WARN[0005] GOT A MESSAGE:message #1                     
WARN[0005] GOT A MESSAGE:message #2                     
WARN[0005] GOT A MESSAGE:message #3                     
WARN[0005] GOT A MESSAGE:message #4                     
WARN[0005] GOT A MESSAGE:message #5                     
WARN[0005] GOT A MESSAGE:message #6                     
WARN[0005] GOT A MESSAGE:message #7                     
WARN[0005] GOT A MESSAGE:message #8                     
WARN[0305] PAUSE                                        
WARN[0605] received message count=8                     

我的版本信息是 1.4.15。我的 mosquitto.conf 是:

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

allow_anonymous false
password_file /etc/mosquitto/passwd

log_dest file /var/log/mosquitto/mosquitto.log

最初 /var/lib/mosquitto/mosquitto.db 直到运行了几次迭代后才会显示。我的测试应用在这里:

import (
    mqtt "github.com/eclipse/paho.mqtt.golang"
    log "github.com/sirupsen/logrus"
    "time"
)

var receivedMsg int

func Persist() {
    const TOPIC = "test"
    const URL = "tcp://localhost:1883"
    const USERNAME = "myuser"
    const PASSWORD = "mypassword"

    defer printReceived()

    options := mqtt.NewClientOptions().AddBroker(URL).SetUsername(USERNAME).SetPassword(PASSWORD)
    options.SetCleanSession(false)
    options.SetConnectRetry(true)
    options.SetConnectRetryInterval(10 * time.Millisecond)

    // register the receive client with broker / TOPIC
    // to be sure the broker knows it needs to save our messages
    // to deliver at a later time
    options.SetClientID("receive-client")
    client := mqtt.NewClient(options)
    token := client.Connect()
    token.Wait()
    if token := client.Subscribe(TOPIC, 2, consume1); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }
    client.Disconnect(0)

    // connect with send client and send 10 messages
    options.SetClientID("send-client")
    client = mqtt.NewClient(options)
    token = client.Connect()
    token.Wait()

    client.Publish(TOPIC, 2, false, "message #1")
    client.Publish(TOPIC, 2, false, "message #2")
    client.Publish(TOPIC, 2, false, "message #3")
    client.Publish(TOPIC, 2, false, "message #4")
    client.Publish(TOPIC, 2, false, "message #5")
    client.Publish(TOPIC, 2, false, "message #6")
    client.Publish(TOPIC, 2, false, "message #7")
    client.Publish(TOPIC, 2, false, "message #8")
    client.Publish(TOPIC, 2, false, "message #9")
    client.Publish(TOPIC, 2, false, "message #10")
    client.Disconnect(4)
    time.Sleep(5* time.Second)

    // subscribe again and try to retrieve the messages we missed
    options.SetClientID("receive-client")
    client = mqtt.NewClient(options)
    token = client.Connect()
    token.Wait()

    if token := client.Subscribe(TOPIC, 2, consume2); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }

    time.Sleep(300 * time.Second)
    log.Warn("PAUSE")
    time.Sleep(300 * time.Second)
}

func consume1(client mqtt.Client, msg mqtt.Message) {
    receivedMsg++
    log.Warn("THIS SHOULD NOT BE CONSUMING ANY MESSAGES:", string(msg.Payload()))
}

func consume2(client mqtt.Client, msg mqtt.Message) {
    receivedMsg++
    log.Warn("GOT A MESSAGE:", string(msg.Payload()))
}

func printReceived() {
    log.Warn("received message count=", receivedMsg)
}

【问题讨论】:

    标签: go mqtt mosquitto


    【解决方案1】:

    在 QOS 2 上发布是一个多步骤过程,因此最可能的原因是您在所有消息真正完成发布到代理之前断开了发布客户端的连接。 您可能应该在循环中执行该发布,并使用从调用 client.publish() 返回的令牌等到它完成后再断开客户端连接。

    例如如示例所示:

    //Publish 5 messages to /go-mqtt/sample at qos 1 and wait for the receipt
    //from the server after sending each message
    for i := 0; i < 5; i++ {
      text := fmt.Sprintf("this is msg #%d!", i)
      token := c.Publish("go-mqtt/sample", 0, false, text)
      token.Wait()
    }
    

    【讨论】:

    • 当然!我将其生成为服务器的简单表示,并且服务器发布 goroutine(以便我可以异步发布)不受 WaitGroup 保护。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    相关资源
    最近更新 更多