Is MQTT reliable over unreliable connection, such as a wifi-to-uart bridge? - mqtt

I'm applying MQTT on an IoT device. A WiFi-to-UART bridge is used to provide wireless network connection between a main controller MCU and the MQTT broker. To simplify the code on the MCU, the TCP connection is managed on the WiFi-to-UART bridge. However, since the WiFi-to-UART bridge does not support MQTT, the MQTT client runs on the MCU.
Now, the connection between the MCU and broker goes through UART, which is unreliable. Random error and lost may happen at a low but not zero chance. Is MQTT still reliable in this situation? If I set the MQTT QoS level to 2, does it still guarantee exactly one delivery of each message? Is the content still guaranteed to be right?

The MQTT protocol specifies the following regarding QOS level 2:
In the QoS 2 delivery protocol, the sender:
MUST assign an unused Packet Identifier when it has a new Application Message to publish [MQTT-4.3.3-1].
MUST send a PUBLISH packet containing this Packet Identifier with QoS 2 and DUP flag set to 0 [MQTT-4.3.3-2].
MUST treat the PUBLISH packet as “unacknowledged” until it has received the corresponding PUBREC packet from the receiver [MQTT-4.3.3-3]. Refer to section 4.4 for a discussion of unacknowledged messages.
MUST send a PUBREL packet when it receives a PUBREC packet from the receiver with a Reason Code value less than 0x80. This PUBREL packet MUST contain the same Packet Identifier as the original PUBLISH packet [MQTT-4.3.3-4].
MUST treat the PUBREL packet as “unacknowledged” until it has received the corresponding PUBCOMP packet from the receiver [MQTT-4.3.3-5].
MUST NOT re-send the PUBLISH once it has sent the corresponding PUBREL packet [MQTT-4.3.3-6].
MUST NOT apply Message expiry if a PUBLISH packet has been sent [MQTT-4.3.3-7].
And:
In the QoS 2 delivery protocol, the receiver:
MUST respond with a PUBREC containing the Packet Identifier from the incoming PUBLISH packet, having accepted ownership of the Application Message [MQTT-4.3.3-8].
If it has sent a PUBREC with a Reason Code of 0x80 or greater, the receiver MUST treat any subsequent PUBLISH packet that contains that Packet Identifier as being a new Application Message [MQTT-4.3.3-9].
Until it has received the corresponding PUBREL packet, the receiver MUST acknowledge any subsequent PUBLISH packet with the same Packet Identifier by sending a PUBREC. It MUST NOT cause duplicate messages to be delivered to any onward recipients in this case [MQTT-4.3.3-10].
MUST respond to a PUBREL packet by sending a PUBCOMP packet containing the same Packet Identifier as the PUBREL [MQTT-4.3.3-11].
After it has sent a PUBCOMP, the receiver MUST treat any subsequent PUBLISH packet that contains that Packet Identifier as being a new Application Message [MQTT-4.3.3-12].
MUST continue the QoS 2 acknowledgement sequence even if it has applied message expiry [MQTT-4.3.3-13].
And
When a Client reconnects with Clean Start set to 0 and a session is present, both the Client and Server MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL packets using their original Packet Identifiers. This is the only circumstance where a Client or Server is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at any other time [MQTT-4.4.0-1].
I can't tell if you are using a library or implementing this yourself or if you are receiver or sender from your question.
But if you are a sender as long as you haven't received a publish acknowledgement(PUBREC) and you manage to reconnect you should republish any messages that haven't been acknowledged.
And if you are a receiver you should keep receiving the message until you respond with a publish received(also PUBREC). If you have already received the message you should resend the publish received.
I am not sure how libraries handle QoS 2 when the connection drops in he middle of the exchange. It seems likely that they will try to reconnect but this is something you should probably check up on the the library documentation if you use one. This might also differ from library to library.
It also might be worth looking into the retain feature for a publish.
This could ensure that the most recent message is retained on the server/broker in case you cant receive it at the moment due to connection issues.

Related

MQTT 5 message delivery retry

I read though the MQTT 5 specs but it didn't answer my questions. I am talking about "4.4 Message delivery retry" of the specs. What happens if your client uses no session (cleanStart = true) and the connection gets lost immediately after sending a QoS 2 PUBLISH packet (no PUBREC was received by the client)?
When a Client reconnects with Clean Start set to 0 and a session is
present, both the Client and Server MUST resend any unacknowledged
PUBLISH packets (where QoS > 0) and PUBREL packets using their
original Packet Identifiers. This is the only circumstance where a
Client or Server is REQUIRED to resend messages. Clients and Servers
MUST NOT resend messages at any other time.
The specs describe that the client MUST NOT resend the message. So how does MQTT 5 guarantee that the message will be received by the receiver?
Sources:
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html
Clean session set to true means that any unacknowledged messages will be discarded.
By setting it to true the client ID actively say it doesn't care about old messages when it reconnects.
The broker can not guarantee that the message is delivered if the client says it doesn't want it .

MQTT 3.1.1 broker QoS=1 ("at least once") message redelivery

I am trying to find out the reality about MQTT 3.1.1 message re-delivery for messages received by a MQTT subscriber with "at least once" (QoS 1) configuration:
Do MQTT brokers re-deliver un-acknowledged "QoS 1" messages from subscribers?
How much time must pass until MQTT broker re-deliver?
Does the MQTT broker try endlessly to re-deliver an unacknowledged message?
Are there other ways to trigger a re-delivery?
Assuming that a MQTT subscriber does not respond with a PUBACK message to a received MQTT message, the MQTT broker needs (at least from my understanding) re-deliver the message which must be received "at least once" until the subscriber sends a PUBACK for that message.
To get more concrete on what I am trying to achieve:
Is it a good/valid idea to postpone sending the PUBACK until a received message was successfully persisted - effectively enlarging the QoS level until my subscribing application guaranteed that the message was processed.
And whether for e.g. persistence errors (timeouts to the database) no PUBACK would be send which would automatically result in a re-delivery of such messages.
Thx & best regards
Do MQTT brokers re-deliver un-acknowledged "QoS 1" messages from subscribers?
From [the spec]:
When a Client reconnects with CleanSession set to 0, both the Client and Server MUST re-send any unacknowledged PUBLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet Identifiers [MQTT-4.4.0-1]. This is the only circumstance where a Client or Server is REQUIRED to redeliver messages.
So, yes, unacknowledged QOS1 messages will be redelivered but the only time the spec REQUIRES this to happen is when a client reconnects.
While you specificity state you are using MQTT v3.1.1 I believe it is worth noting that MQTT v5 expressly prohibits re-delivery other than following a reconnect:
When a Client reconnects with Clean Start set to 0 and a session is present, both the Client and Server MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL packets using their original Packet Identifiers. This is the only circumstance where a Client or Server is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at any other time
How much time must pass until MQTT broker re-deliver?
As per the above automatic retry is not required by the spec. Some brokers may retransmit after a period of time. emqx supports this; mosquitto used to have an option but this was removed in version 1.5 with the change log explaining:.
Outgoing messages with QoS>1 are no longer retried after a timeout period.
Messages will be retried when a client reconnects. This change in behaviour
can be justified by considering when the timeout may have occurred.
If a connection is unreliable and has dropped, but without one end
noticing, the messages will be retried on reconnection. Sending
additional PUBLISH or PUBREL would not have changed anything.
If a client is overloaded/unable to respond/has a slow connection then
sending additional PUBLISH or PUBREL would not help the client catch
up. Once the backlog has cleared the client will respond. If it is not
able to catch up, sending additional duplicates would not help either
Does the MQTT broker try endlessly to re-deliver an unacknowledged message?
The 3.11 spec does not provide any guidance (so, in theory, yes) but many brokers provide some control over this (maximum number of messages queued, max size of queue etc).
Are there other ways to trigger a re-delivery?
Yes - disconnect and reconnect.
Is it a good/valid idea to postpone sending the PUBACK until a received message was successfully persisted
There was a discussion re this on the paho-dev group a couple of months ago. Its something that is being considered in the Go v5 Client (currently that client automatically acknowledges messages).
One thing to note is that the MQTT spec does have requirements with regards to the order acknowledgments are sent. Many clients ignore this requirement (and just send the acknowledgments whenever the handler returns) but some (e.g. the HiveMQ Java client) queue up ACKs so they can be sent in the correct order.

MQTT QoS2 why use 4 packets?

I think we can just use publish and pubrcv to meet the QoS2.
ClientA-> Server publish packet
Server -> ClientA pubrecv packet
When the server recv the publish packet, save to db, then the server publish to other clients, eg. ClientB.
Even if we recv two same publish packets from ClientA, the server check the db, and know this is repeated message, so not publish to the ClientB.
So I don't think need 4 packets.
Do my logic is correct?
There protocol uses the two exchanges of packets in order to provide the exactly-once semantics of QoS 2 messaging.
C --- PUBLISH --> S
*1
C <-- PUBREC --- S
*2
C --- PUBREL --> S
*3
C <-- PUBCOMP --- S
*4
When the server receives the PUBLISH it stores the ID and forwards the message on. When the server receives the PUBREL it can then delete the ID.
If the connection breaks at *1, the client does not know if the server received the message or not. It resends the PUBLISH (containing the full message payload). If the server had already received the message it just needs to respond with the PUBREC.
If the connection breaks at *2, the client may or may not have received the PUBREC. If it didn't, it will resend the PUBLISH. Otherwise it will send the PUBREL.
If the connection breaks at *3, the client does not know if the server received the message or not. It resends the PUBREL - which does not contain full message payload.
If the connection breaks at *4 and the client hasn't received the PUBCOMP it can resend the PUBREL.
There are two observations for why the two exchanges are needed:
the server is not required to remember every message it has ever seen. There is a very well defined period for it to store the message ID. The two exchanges allow both sides to have certainty that the message has been delivered exactly once.
the client does not need to resend the PUBLISH multiple times (unless the connection is interrupted at *1. Given the protocol is intended to minimise network traffic, this is an important feature.

can mqtt msg delivery order be guaranteed in simplified case?

If there is only a single broker, a single publisher, a single topic and clean session, in this simplified case,
can msg delivery order on subscriber side be guaranteed to be the same as send order on publisher side? Will it be affected by QoS?
Section 4.6 from the MQTT 3.1.1 spec covers message ordering:
4.6 Message ordering
A Client MUST follow these rules when implementing the protocol flows
defined elsewhere in this chapter:
When it re-sends any PUBLISH packets, it MUST re-send them in the order in which the original PUBLISH packets were sent (this applies to
QoS 1 and QoS 2 messages) [MQTT-4.6.0-1]
It MUST send PUBACK packets in the order in which the corresponding PUBLISH packets were received (QoS 1 messages)
[MQTT-4.6.0-2]
It MUST send PUBREC packets in the order in which the corresponding PUBLISH packets were received (QoS 2 messages)
[MQTT-4.6.0-3]
It MUST send PUBREL packets in the order in which the corresponding PUBREC packets were received (QoS 2 messages)
[MQTT-4.6.0-4]
A Server MUST by default treat each Topic as an "Ordered Topic". It
MAY provide an administrative or other mechanism to allow one or more
Topics to be treated as an "Unordered Topic" [MQTT-4.6.0-5].
When a Server processes a message that has been published to an
Ordered Topic, it MUST follow the rules listed above when delivering
messages to each of its subscribers. In addition it MUST send PUBLISH
packets to consumers (for the same Topic and QoS) in the order that
they were received from any given Client [MQTT-4.6.0-6].
Having read that I would conclude that messages will normally (unless the broker specifically set to use unordered topics) be sent in order, but if a high QOS message is not acknowledged properly it may be resent which could result in it being redelivered out of sequence.

Is message order preserved in MQTT messages?

I wonder if the message sent order is preserved. That is, when a publisher sends a sequence of messages, is each subscriber guaranteed to receive the same sequence as the publisher had sent it? For both clean and persistent sessions?
A summary of the message ordering capabilities in MQTT 3.1.1 can be found in the specification itself here.
In summary:
no guarantees are made about the relative ordering of messages published with different QoS values. (for example, QoS 0 can over take QoS 2 for example as it involves a single packet rather than the 4 packets of the latter).
QoS 0 messages will be delivered in order (albeit messages may get lost)
QoS 2 messages will be delivered in order
QoS 1 allows for message duplicates - it is possible a duplicate will arrive after the first instance of the next message that was published.
QoS 1 ordering can be guaranteed if the client/broker only allow a single message inflight at any time.
when a publisher sends a sequence of messages, is each subscriber guaranteed to receive the same sequence as the publisher had sent it?
This question has already been answered and well accepted but I see an issue with the following statement in the accepted answer.
QoS 2 messages will be delivered in order
As per the documentation, it is mentioned the sequence of packets PUBLISH,PUBREC, PUBREL, PUBCOMP will be maintained per topic across QOS 2 level messages. However, a subscriber can still receive in different order than published by publisher (possible but rare). The same logic is also applicable for QOS 1.
Let's see how:
PUBLISH packet has been send by broker for message m1.
PUBLISH packet has been send by broker for message m2.
PUBREC packet has been send by subscriber for message m1.
PUBREC packet has been send by subscriber for message m2.
PUBREL packet has been send by broker for message m1. But it got dropped.
PUBREL packet has been send by broker for message m2.
PUBCOMP packet has been send by subscriber for message m2.
Timeout for PUBREL packet at the broker has occurred for message m1. Broker will retry for message m1.
Broker re-transmits PUBREL packet for message m1.
PUBCOMP packet has been send by subscriber for message m1.
By above sequence, there is an possibility of the message m2 being processed first at the receiver. However, m1 was published before m2.
See this answer for further details.
Picture taken from u-blox.

Resources