-
Type: Improvement
-
Status: Closed
-
Priority: Major
-
Resolution: No Action
-
Affects Version/s: 5
-
Fix Version/s: None
-
Component/s: candidateCN
-
Labels:None
1) Today, there is no described mechanism for documenting how a client should work with multiple servers (brokers).
I propose that we solve many variants of this common problem with a committee note that documents the use of DNS SRV records with MQTT. Alternative approaches require protocol changes (something that didn't work well in AMQP 0-8), or the use of server-side redirects using URIs (something that went quite wrong with AMQP).
2) SRV records capture four very valuable pieces of information that a client needs:-
1 - The set of servers it should connect with, and the relative weighting of them (the weighting reflects, roughly, the server's resource availability, eg 'number of CPUs' or 'network bandwidth')
2 - The priority given to this set of servers. SRV records allow multiple sets of servers, each with lower priority. This allows documentation of priority, ie, try, this set of servers then this set. Typically used for fallover from a production set to a temporary set or last-resort backup.
3 - For a given server in a set, the list of A, AAAA or CNAME records to use. This allows the incorporation of DNS round-robin, multiple NICs / routes, IPv4 / IPv6 alternatives, etc. DNS round-robin itself is plagued with issues, not least interpretation of the meaning of the list.
4 - The port to use for this server entry. This allows local overrides, even multi-hosting on the same server (using CNAME records associated with different ports).
One can see the first three points as a hierarchy:-
- Priority Group 1
- Server Set 1.1, 60% of the time
- A record
- IP 192.168...
- IP 10.0....
- AAAA record
- ...
- CNAME record
- ...
- Server Set 1.2, 40% of the time
- Priority Group 2
- Server Set 2.1
- Server Set 2.2
3) How do you use a DNS record?
Simple, look it up with a syntax such as
_mqtt._tcp.stormmq.com. 86400 IN SRV 0 5 5060 mqtt1.stormmq.example.com.
See wikipedia: https://en.wikipedia.org/wiki/SRV_record
4) SRV records make it much easier to manage long-term set ups.
If we add connectionless MQTT-SN over UDP, they work for those too.
5) What SRV records can't do:-
- tell us a server uses TLS or not (one can look up _mqtts, but that's not ideal)
- tell us what security arrangements to use (eg if we add SASL, what SASL cert to use).
- dynamically reflect server load, although, if given a short TTL (eg 120 seconds), they can be semi-dynamic. Given that MQTT connections are typically long-lived, there is the possibility of inequality building up on one server. Republishing to
6) However, they can work well in conjunction with three other DNS record types:-
- LOC, to allow clients who know their geographic co-ordinates to find their nearest server (one can add LOC records for both the SRV record name and the individual CNAMEs used in server sets)
- DANE, to allow secure publication of X.509 certificates for MQTT brokers using TLS;
- TXT, to publish other data such as supported SASL mechanisms (although I'm hessitant about this; it is only secure if using secured DNS infrastructure, as otherwise a malicious MITM DNS resolver can change it)
I am more hessitant about recommending the use of these generally, but they could certainly be entered into a committee note.
7) Adapting existing clients
All the logic for working with SRV records can happen before connection, and when a reconnection is desired; there is no protocol impact. Working with SRV records isn't a lot of fun (one typically has to write the logic ones self for the subsequent look ups and application of weightings - pick a random number between 1 - 100 and see which weighting should be used, then remove the weighting for another connection attempt), but Paho is well-placed to write this logic once per language.
8) Adapting existing servers
These can decide to publish, if they want, weightings to DNS. The choice is theirs.
8) If we extended the protocol
We can add a CONNACK return code of 'try another server'. This can be used when a server is heavily loaded. Doing this, rather than have the server return which other servers to try (which means needing a URI protocol that works), means the servers do not have to manage the cluster list - typically a win. Servers would still have to share session state with each other, but there are ways and means to do this...
If we also add a CONNACK code of 'upgrade to TLS', then clients have to know nothing more than which authentication mechanism to use (currently anonymous, username only or password; in the future, SASL mechanism)