Understanding mqtt subscriber qos - publish-subscribe

I am new to MQTT and I just learned about the meaning of the QOS level that is decided when a message is published:
0 when we prefer that the message will not arrive at all rather than arrive twice
1 when we want the message to arrive at least once but don't care if it arrives twice (or more)
2 when we want the message to arrive exactly once.
A higher QOS value means a slower transfer
I noticed that the subscriber side can also set the "Maximum QOS level they will receive".
Quoting from here:
For example, if a message is published at QoS 2 and a client is subscribed with QoS 0, the message will be delivered to that client with QoS 0.
Does this mean that the message might not arrive to the client (QOS 0) despite the fact that publisher sent it with QOS 2?
This might be a big issue among inexperienced developers - for example, the default QOS of the subscribe function in the npm mqtt package is 0! (The default should have been the maximum value 2 in my opinion, i.e. "let the publisher decide the QOS").

You are correct, there is no guarantee that a message published at QoS 2 will arrive at a subscriber who is using QoS 0. If it is important for that subscriber to receive the message, they should be using QoS 1 or 2. That is something to decide for any given application.
I would rewrite your definition of QoS 0 as "at most once", i.e. the message will be received or it won't, there isn't a chance of a duplicate.
Regarding default QoS - I think most clients use QoS 0 as the default. I don't see that setting QoS 1 or 2 as the default would help the inexperienced developer, they still need to understand why and what they are doing and to consider the implications on their application.

A publisher really doesn't have a direct notion of what clients are subscribed to that message. A publisher's QOS level determines the quality of service in ensuring that the broker receives the publication. Once the broker receives the publication, it becomes responsible to re-send the message.
[edit] The broker then resends the message to the subscribers, but only at most at the QoS that it received from the publisher. This may even be a downgrading of QoS that subscribers have specified.
I found this article quite helpful in understanding this concept.

"Does this mean that the message might not arrive to the client (QOS 0) despite the fact that publisher sent it with QOS 2?"
Yes that is true. The publisher will want to publish at QOS 2 to ensure that the record arrives at the state layer only once (without duplicates). A layer of retrys + acks are used to ensure this. There is additional work for the brokers that provide the topic to subscribing clients to ensure that the message is delivered at the requested QOS level.
For example a message is published at QOS 1 and a subscriber to the same topic is subscribed at QOS 2, then the broker handling the delivery of the message to said subscriber will have to ensure that no duplicate is sent to the client.
In your example a publisher is publishing at QOS 2, so the state layer inserted the record once, and there is a subscriber at QOS 0 for this same topic. The subscriber may never receive this message. For example during message send there was a network hiccup and the record never arrived. Since there is no ack mechanism in QOS 0 the broker never attempts to redeliver.

i did't read MQTT protocol Specifications yet,
just say my test with mosquitto 1.5.3.
1. run mosquitto server/broker
with default conf.
mosquitto -v
1541075091: mosquitto version 1.5.3 starting
1541075091: Using default config.
2. pub test msg
AAA sub topic 'aaa'
BBB sub topic '+'
DDD pub topic 'aaa'
3. the server stdout
1541075322: New connection from 10.1.1.159 on port 1883.
1541075322: New client connected from 10.1.1.159 as DDD (c1, k60).
1541075322: No will message specified.
1541075322: Sending CONNACK to DDD (0, 0)
1541075322: Received PUBLISH from DDD (d0, q1, r1, m1, 'aaa', ... (8 bytes))
1541075322: Sending PUBACK to DDD (Mid: 1)
1541075322: Sending PUBLISH to AAA (d0, q0, r0, m0, 'aaa', ... (8 bytes))
1541075322: Sending PUBLISH to BBB (d0, q0, r0, m0, 'aaa', ... (8 bytes))
1541075322: Received DISCONNECT from DDD
1541075322: Client DDD disconnected.
server PUBACK to DDD before PUBLISH the msg.
4. so i guess
pub qos=1 only make sure broker received the msg,
sub qos also:
[ pub ] ---pub_qos---> [ broker ] ---sub_qos--> [ sub ]
// MQTT clients and broker Network topology is star network.
// if i have time, i'll read the Protocol Specifications

Related

MessagesKilled on DLQ

I have a DLQ with a large amount of "Messages killed". The broker is a single node. There is no cluster.
According to this documentation "Messages killed" is :
Amount of messages that have been killed on the broker to exceeding the max delivery attempts and is collected form the sum of subcomponent=queues#MessagesKilled for all queues.
What use case is ActiveMQ Artemis trying to solve? Why on earth does DLQ have any amount of Messages killed? I expect this value to be 0 initially anyway.
Attributes:
Acknowledge attempts 68890
Address DLA
Configuration managed false
Consumer count 0
Consumers before dispatch 0
Dead letter address DLA
Delay before dispatch -1
Delivering count 0
Delivering size 0
Durable true
Durable delivering count 0
Durable delivering size 0
Durable message count 1539
Durable persistent size 2183288
Durable scheduled count 0
Durable scheduled size 0
Enabled true
Exclusive false
Expiry address ExpiryQueue
...
Group buckets -1
Group count 0
Group first key
Group rebalance false
Group rebalance pause dispatch false
Id 1006063
Last value false
Last value key
Max consumers -1
Message count 1539
Messages acknowledged 0
Messages added 70429
Messages expired 0
Messages killed 68890
Name jms.queue.satellitanalys_request.DLQ
Object Name org.apache.activemq.artemis:broker="0.0.0.0",component=addresses,address="DLA",subcomponent=queues,routing-type="multicast",queue="jms.queue.satellitanalys_request.DLQ"
Paused false
Persistent size 2183288
Prepared transaction message count 0
Purge on no consumers false
Retroactive resource false
Ring size -1
Routing type MULTICAST
Scheduled count 0
Scheduled size 0
Temporary false
User
The actual description of "Messages killed" can be acquired from the MBean itself which states:
number of messages removed from this queue since it was created due to exceeding the max delivery attempts
Generally speaking, the use-case being solved here is a message which cannot be consumed (for whatever reason) is being removed from the queue (i.e. killed) so that the consumer can receive, and hopefully successfully process, a different message. The behavior is 100% configurable in broker.xml.
There are a handful of important metrics here:
Acknowledge attempts 68890
Message count 1539
Messages acknowledged 0
Messages added 70429
Messages killed 68890
Acknowledge "attempts" and actual acknowledgements are tracked independently because, for example, a message may be acknowledged in a transaction and then that transaction can be rolled back in which case the message won't actually be acknowledged. That appears to be the case here since there have been 68,890 attempts to acknowledge but 0 actual acknowledgements. I can only assume that the max-delivery-attempts for this queue is 1 since there are also 68,890 killed messages. Notice too that the number of messages added is 70,429 which corresponds to the message count of 1,539 (i.e. 70,429 - 68,890 = 1,539). Everything seems to be accounted for.
My conclusion is that you have (or had) a consumer that is (or was) attempting to consume messages from this queue via a transaction, and that transaction was rolled back in every instance.
Keep in mind that a "dead-letter queue" is just a normal queue like any other. All the same configuration and semantics apply to it as they would apply to any other queue.

Feedback message from subscriber in mqtt protocol

I used the MQTT protocol to send messages between two computers. I have patterned from this code.
publisher:
import paho.mqtt.client as mqtt
from random import randrange, uniform
import time
mqttBroker ="mqtt.eclipse.org"
client = mqtt.Client("Temperature_Inside")
client.connect(mqttBroker)
while True:
randNumber = randrange(10)
client.publish("TEMPERATURE", randNumber)
print("Just published " + str(randNumber) + " to topic TEMPERATURE")
time.sleep(1)
subscriber:
import paho.mqtt.client as mqtt
import time
def on_message(client, userdata, message):
print("received message: " ,str(message.payload.decode("utf-8")))
mqttBroker ="mqtt.eclipse.org"
client = mqtt.Client("Smartphone")
client.connect(mqttBroker)
client.loop_start()
client.subscribe("TEMPERATURE")
client.on_message=on_message
time.sleep(1)
client.loop_stop()
I want a feedback to be sent to the publisher when I receive the message. Is there a way to get message feedback?
There is no end to end delivery notification in the MQTT protocol. This is very deliberate.
MQTT is a pub/sub system, designed to totally separate the producer of information from the consumer. There could be 0 to infinite number of subscribers to a topic when a producer publishes a message. There could also be offline subscribers who will have the message delivered when they reconnect (which could be any time after the message was published)
What MQTT does provide is the QOS levels, but it is important to remember that these only apply to a single leg of the delivery journey. E.g. a message published at QOS 2 ensures it will reach the broker, but makes no guarantees about any subscribers as their subscription may be at QOS 0.
If your system requires end to end delivery notification then you will need to implement a response message yourself, this is normally dinner by including a unique ID in the initial message and sending a separate response message in a different topic also containing that ID
To ensure your message will get delivered you can use QoS. This can be set when publishing or subscribing. So for your case you will want either QoS 1 or 2. QoS 2 ensures it will reach the broker exactly once when publishing, and if subscribed at QoS 2 it will ensure the subscriber gets the message exactly once. Note though QoS 2 is the slowest form of publishing and subscribing. I find the most common way to deal with messages is with QoS 1, and then in your subscribe on_message you can determine how to deal with duplicate messages yourself. The paho mqtt client allows you to set QoS when publishing or subscribing but it defaults to 0. I've updated your code below.
# publisher
import paho.mqtt.client as mqtt
from random import randrange, uniform
import time
import json
mqttBroker ="mqtt.eclipse.org"
client = mqtt.Client("Temperature_Inside")
client.connect(mqttBroker)
id = 1
while True:
randNumber = randrange(10)
message_dict = { 'id': id, 'value': randNumber }
client.publish("TEMPERATURE", json.dumps(message_dict), 1)
print("Just published " + str(randNumber) + " to topic TEMPERATURE")
id += 1
time.sleep(1)
# subscriber
import paho.mqtt.client as mqtt
import time
import json
from datetime import datetime
parsed_messages = {}
def on_message(client, userdata, message):
json_body = json.loads(str(message.payload.decode("utf-8")))
msg_id = json_body['id']
if msg_id in parsed_messages.keys
print("Message already recieved at: ", parsed_messages[msg_id].strftime("%H:%M:%S"))
else
print("received message: " ,json_body['value'])
parsed_messages[msg_key] = datetime.now()
mqttBroker ="mqtt.eclipse.org"
client = mqtt.Client("Smartphone")
client.connect(mqttBroker)
client.loop_start()
client.subscribe("TEMPERATURE", 1)
client.on_message=on_message
time.sleep(1)
client.loop_stop()
Note it is important that the subscriber also defines QoS 1 on subscribing otherwise it will subscribe with QoS 0 which is default for the paho client, and the message will get downgraded to 0, meaning the message will get delivered at most once (but may not get delivered at all if packet dropped). As stated the above only ensures that the message will get received by the subscriber. If you want the publisher to get notified when the subscriber has processed the message you will need to publish on a new topic (with some uuid) when the subscriber has finished processing that the publisher can subscribe to. However when I see this being done I often question why use MQTT, and not just send HTTP requests. Here is a good link on MQTT QoS if you're interested (although it lacks detail on what happens from subscriber side).

max-delivery-attempts does not work for un-acknowledged messages

I noted strange behavior in Artemins. I'm not sure if this is a bug or if I don't understand something.
I use Artemis Core API. I set autoCommitAcks to false. I noted that If message is received in MessageHandler but message is not acknowledged and session is rollbacked then Artemis does not consider this message as undelivered, Artemis consider this message as not sent to consumer at all. Parameter max-delivery-attempts does not work in this case. Message is redelivered an infinite number of times. Method org.apache.activemq.artemis.api.core.client.ClientMessage#getDeliveryCount returns 1 each time. Message has false value in Redelivered column in web console. If message is acknowledged before session rollback then max-delivery-attempts works properly.
What exactly is the purpose of message acknowledge? Acknowledge means only that message was received or acknowledge means that message was received and processed successfully? Maybe I can use acknowledge in both ways and it only depends on my requirements?
By message acknowledge I mean calling org.apache.activemq.artemis.api.core.client.ClientMessage#acknowledge method.
The behavior you're seeing is expected.
Core clients actually consume messages from a local buffer which is filled with messages from the broker asynchronously. The amount of message data in this local buffer is controlled by the consumerWindowSize set on the client's URL. The broker may dispatch many thousands of messages to various clients that sit in these local buffers and are never actually seen in any capacity by the consumers. These messages are considered to be in delivery and are not available to other clients, but they are not considered to be delivered. Only when a message is acknowledged is it considered to be delivered to a client.
If the client is auto-committing acknowledgements then acknowledging a message will quickly remove it from its respective queue. Once the message is removed from the queue it can no longer be redelivered because it doesn't exist anymore on the broker. In short, you can't get configurable redelivery semantics if you auto-commit acknowledgements.
However, if the client is not auto-committing acknowledgements and the consumer closes (for any reason) without committing the acknowledgements or calls rollback() on its ClientSession then the acknowledged messages will be redelivered according to the configured redelivery semantics (including max-delivery-attempts).

Redelivery from queue is unordered in ActiveMQ Artemis

If ActiveMQ Artemis is configured with a redelivery-delay > 0 and a JMS listener uses ctx.rollback() or ctx.recover() then the broker will redeliver the message as expected. But if a producer pushes a message to the queue during a redelivery then the receiver gets unordered messages.
For example:
Queue: 1 -> message 1 is redelivered as expected
Push during the redelivery phase
Queue: 2,3 -> the receiver gets 2,3,1
With a redelivery-delay of 0 everything is ok, but the frequency of redeliveries on consumer side is too high. My expectation is that every delivery to the consumer should be stopped until the unacknowledged message is purged from the queue or acknowledged. We are using a queue for connection with single devices. Every device has it's own I/O queue with a single consumer. The word queue suggest strict ordering to me. It could be nice to make this behavior configurable like "strict_redelivery_order".
What you're seeing is the expected behavior. If you use a redelivery-delay > 0 then delivery order will be broken. If you use a redelivery-delay of 0 then delivery order will not be broken. Therefore, if you want to maintain strict order then use a redelivery-delay of 0.
If the broker blocked delivery of all other messages on the queue during a redelivery delay that would completely destroy message throughput performance. What if the redelivery delay were 60 seconds or 10 minutes? The queue would be blocked that entire time. This would not be tenable for an enterprise message broker serving hundreds or perhaps thousands of clients each of whom may regularly be triggering redeliveries on shared queues. This behavior is not configurable.
If you absolutely must maintain message order even for messages that cannot be immediately consumed and a redelivery-delay of 0 causes redeliveries that are too fast then I see a few potential options (in no particular order):
Configure a dead-letter address and set a max-delivery-attempts to a suitable value so after a few redeliveries the problematic message can be cleared from the queue.
Implement a delay of your own in your client. This could be as simple as catching any exception and using a Thread.sleep() before calling ctx.rollback().

How do you address messages coming out of order in a message queue?

I was once asked on an interview, how would you deal with messages coming in out of order in a message queue. It has been a while and I have not found a definitive answer and I was wondering if an expert in the field can help me answer it to address my own curiosity.
I understand that some message queues provide exactly-once and FIFO guarantees. Also I am aware of the notion of event time and processing time in streaming systems. For instance, in log based message queues like Kafka, mixed up ordering may be less likely to happen due to the presence of offsets and message durability (I may be wrong). I have also thought about using timestamps requiring each message sender to record the time of message before sending it but this is fraught with inconsistency due to clock skew.
Given all of that, I am wondering how can one address mixed up ordering in a traditional messaging system like AMQP, JMS or RabbitMQ where a dozen of IOT devices may be sending messages and I as a consumer want to reconcile them in the correct order.
If queue your system is using, provides ordered message guarantee, then simply use that channel(like kakfa's single partition, AMQP under some settings).
But if queue your system is using does not provide strict ordering then general Idea is that client can have monotonically increasing[1] number(or timestamp) attached with each message it sends to queue. This forms the basis of sequence which producer intends to send to its receivers.
How to get montonically increasing value:
Using timestamp:
POSIX clock_gettime() function with CLOCK_MONOTONIC[2] provides option to get monotonically increasing timestamp, which can be used by producer to put timestamp on each message. Receiver can identify out of order messages when it sees that received message has timestamp older than latest message.
Using sequence number:
Before sending each message you can simply increase an atomic counter and attach counter value to each message, so that receiver can know about intended ordering. This will form strictly increasing sequence. Approach is very similar to Lamport's logical clock[3] which provides virtual clock for producer.
Dealing with out of order messages on receiver side:
This is pretty much application specific but in general you have 2 options when messages arrive out of order:
a) discard the older message, like in cases in which receiver have to show latest value of a stock.
b) Have buffer to reorder sequencing, like within a TCP connection(e.g. zookeeper uses TCP as queue for FIFO ordering [4-5])
Tools:
If you are not adding timestamp to messages, then send all messages to Apache kafka single partition in sequence from producer, as this will ensure that receiver can receive messages in sequence.
If you are using messaging system which does not guarantee ordered delivery (like AMQP under some settings[6]), then you can consider adding additional monotonically increasing number/clock with each message.
[1] https://en.wiktionary.org/wiki/monotonic_increasing#targetText=Adjective,contrast%20this%20with%20strictly%20increasing
[2] https://linux.die.net/man/2/clock_gettime
[3] https://en.wikipedia.org/wiki/Lamport_timestamps#Lamport's_logical_clock_in_distributed_systems
[4] https://cwiki.apache.org/confluence/download/attachments/24193445/zookeeper-internals.pdf?version=1&modificationDate=1295034038000&api=v2
[5] http://www.tcs.hut.fi/Studies/T-79.5001/reports/2012-deSouzaMedeiros.pdf
[6] RabbitMQ - Message order of delivery
I can answer with respect to Apache Kafka.
Apache Kafka guarantees strict order on a topic by partition means each partition is an immutable sequence of message appending in a strict order.
So in case, more than one partition consumer may consume messages from more than one partition which can't be in strict order. We can consider below 2 options to achieve strict order.
If looking for 1 producer message in order use only 1 partition per topic. so the producer will publish on the same partition in sequence order which will get consumed by consumers in strict order.
Producer publishes a message to multi-partition, so use multi-consumer in consumer group but use assign to specific partition per consumer to consume message from specific partition will guarantee strict order per partition per consumer