7

当 MQTT 代理或客户端出现问题时,我有许多 QoS2 级别的消息在场景中导致问题。这些问题可能包括

  • 客户端开始看到服务器超时
  • 客户端已失去与代理的连接(互联网连接断开,代理出现问题,......)一段时间并重新连接。

通常,当 MQTT 客户端开始从代理接收超时或其他错误时,消息将存储在持久性存储中(运行中的消息)并最终重新发布。

但是,在 Paho 客户端失去与代理的连接的情况下,消息将不再被视为在传输中,并且不会被 Paho 存储。在这一点上,应用程序似乎负责保存这些消息(在 paho 之外)并重新发布它们。

我是否正确地说,当 MQTT 代理不可用时,Paho MQTT 客户端无法帮助我保证这些 QoS2 级别的消息将被重新传递?

那么我该如何区分以下情况,其中 client.publish 导致了 MqttException ,其中 Paho 没有持续发送消息。

Client is currently disconnecting (32102)
    at org.eclipse.paho.client.mqttv3.internal.ClientComms.shutdownConnection(ClientComms.java:297)
    at org.eclipse.paho.client.mqttv3.internal.CommsSender.handleRunException(CommsSender.java:154)
    at org.eclipse.paho.client.mqttv3.internal.CommsSender.run(CommsSender.java:131)
    at java.lang.Thread.run(Thread.java:745)

以下是它在飞行中持续存在的地方

Timed out waiting for a response from the server (32000)
    at org.eclipse.paho.client.mqttv3.internal.Token.waitForCompletion(Token.java:94)
    at org.eclipse.paho.client.mqttv3.MqttToken.waitForCompletion(MqttToken.java:50)
    at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:315)
    at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:307)

显然,我也可以开始记账并分别保存所有失败的消息,但最终可能会出现 QoS 级别 2 重复(Paho 和我自己都重新发布的消息)。

客户端应该如何编程?

  • 是否需要基于异常代码与 Paho 一起做我自己的消息持久性?
  • 我是否需要考虑 connectionLost 回调并假设从那时起 Paho 不会为我保留任何东西,直到 MQTT 客户端重新连接?
  • 在发布之前,我是否需要检查客户端是否正确连接,如果是,则假设 Paho 将保留消息?

以下是 Paho 的一些异常和持久性行为

  • 连接丢失 (32109):消息由 paho 持久化
  • 客户端当前正在断开连接 (32102):消息被 paho 丢失
  • 等待服务器响应超时(32000):消息被持久化 paho
  • 客户端未连接 (32104):消息被 paho 丢失

Paho 有哪些最佳实践?

4

2 回答 2

6

我没有设计 Java 客户端,但我可以看到这种行为是如何产生的,并且可能会造成混淆。我假设我们在这里谈论的是同步客户端?调用发布时会遇到所有这些异常吗?

主要原则是:

  1. 如果客户端 API 在要发送消息的位置没有连接(包括断开连接),则不会尝试发送消息,也不会持久化。
  2. 如果客户端 API 当前已连接,则尝试发送消息,并在发送之前将其保留。在 QoS 2 交换完成之前连接可能会失败,其中客户端重新连接时将重试消息。

但是这两种情况都被报告为异常,这是没有帮助的。

在 C 客户端中,我遵循以下规则:

  1. 如果消息被持久化,则返回成功,无论 QoS 2 交换是否完成
  2. 如果客户端断开连接,将调用 connectionLost 回调

所以你知道如果你得到一个错误,你必须重试发布调用。

对于 Java 客户端,我们可以通过以下方式改善这种情况:

  1. 仅当消息未持久化时才抛出异常

或者

  1. 创建另一类异常,清楚地显示消息何时保留和未保留,例如

    • MqttException 超类 - 消息未持久化
    • MqttIncompleteException - 消息被持久化。

请注意,我们计划在 6 月发布 1.2 版“离线缓冲”,这意味着可以在客户端未连接时保留消息。

于 2015-01-25T13:52:45.107 回答
0

至少在使用 android 客户端时,可以肯定离线缓冲将是一个胜利。我已经重用了 paho android 服务中的 sqlite,该服务在服务被单独保留时保留消息,以便在客户端断开连接时保留消息,结果非常好。在考虑更广泛的平台解决方案时,我不知道未来的决定是什么,也许只是在客户端断开连接时允许消息在 QOS2 中的文件/内存持久存储上持久化?不确定当大型消息队列累积并且必须发送时这将如何影响。

于 2015-06-20T08:01:17.557 回答