Round Trips to Authenticate a MongoDB Client Connection
When MongoDB Drivers establish a connection with a MongoDB cluster a number of network round trips are performed. This can result in increased latency when measuring the time to response of an operation following a cold start, so it’s worth understanding what the anatomy of an authenticated connection is - as well as what can be done to improve an initial operations round trip time (RTT).
Current State
Connection Protocol
Typically a MongoDB connection string will contain a standard seed list, which is represented by the mongodb://
protocol followed by a list of servers (ex: mongodb://localhost:27017,localhost:27018....
).
Starting with MongoDB 3.6 instead of having to provide the seed list in the connection string manually a DNS-constructed seed list could be used as well. With this configuration the mongodb+srv://
protocol is used to communicate both the seed list as well as any options by performing two (2) DNS queries to resolve the following DNS records: SRV
and TXT
.
See “MongoDB 3.6: Here to SRV you with easier replica set connections” for more information regarding this topic.
Additionally there may be an RTT for A
/AAAA
/CNAME
resolution, however these may be done in parallel and may also be cached. DNS Caching will likely improve the performance of these queries, but it’s worth noting their presence within the connection establishment and authentication lifecycle.
1
2
/* Network Round Trips */
[0 , 3] // Protocol
Note that if the SRV
record returns multiple hosts, those A
/AAAA
/CNAME
records will be resolved in parallel. And DNS servers typically will optimize the traversal returning any intermediate CNAME
s followed by the A
/AAAA
in the same request.
This also assumes UDP-based DNS resolution. If you exceed the UDP packet size, you might first try UDP, receive an error, and retry using TCP (and possibly requiring a TCP handshake to the DNS server as well).
TCP Handshake
Source: makeuseof.com
Once a host is known from the seed list, next we need to connect to it. This is done using a standard TCP 3-way Handshake, which constitutes 1 RTT. Note that as there is an ACK
sent following the SYN/ACK
this handshake is sometimes considered to be 1.5 RTT, however most TCP stacks will send the first data packet with the ACK
.
1
2
3
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
TLS Handshake
Source: cloudflare.com
To ensure all connections to MongoDB Atlas are secure, Transport Layer Security (TLS) is enabled by default. Following a successful TCP handshake, a TLS handshake will be performed.
1
2
3
4
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 2 // TLS
MongoDB Handshake
Now that we have established a TLS secured TCP socket connection to a MongoDB host (mongos
or mongod
), the MongoDB Driver will send a hello
command to perform the initial handshake.
This step is required to determine that the host at the other end of the socket is actually a MongoDB server. Assuming the version of the MongoDB Driver supports MongoDB 4.4+ the handshake will also include a speculativeAuthenticate
argument. Specifying this argument to hello
will speculatively include the first command of an authentication handshake, thus eliminating one round trip as the saslStart
command doesn’t need to be sent during the authentication handshake.
1
2
3
4
5
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 2 // TLS
+ 1 // MongoDB
Authentication Handshake
MongoDB supports a number of SASL (Simple Authentication and Security Layer) mechanisms. By default the SASL mechanism that will be used will be a SCRAM mechanism (either SCRAM-SHA-1
or SCRAM-SHA-256
), which effectively means “username and password”. Note that this is a “challenge response” mechanism, so these credentials aren’t broadcast in the clear.
As outlined in the MongoDB Authentication specification, a SCRAM-SHA-256
conversation will be made up of 2 round trips as follows:
1
2
3
4
>> {saslStart: 1, mechanism:"SCRAM-SHA-256", options: {skipEmptyExchange: true}, payload: BinData(0, "...=")}
<< {conversationId: 1, payload: BinData(0, "...="), done: false, ok: 1}
>> {saslContinue: 1, conversationId: 1, payload: BinData(0, "...==")}
<< {conversationId: 1, payload: BinData(0, "...=="), done: true, ok: 1}
For backwards compatibility with MongoDB 4.2 or earlier, MongoDB Drivers support a longer SCRAM
conversation which includes an additional saslContinue
command being sent as follows:
1
2
3
4
5
6
>> {saslStart: 1, mechanism: "SCRAM-SHA-1", payload: BinData(0, "..."), options: {skipEmptyExchange: true}}
<< {conversationId : 1, payload: BinData(0,"..."), done: false, ok: 1}
>> {saslContinue: 1, conversationId: 1, payload: BinData(0, "...")}
<< {conversationId: 1, payload: BinData(0,"..."), done: false, ok: 1}
>> {saslContinue: 1, conversationId: 1, payload: BinData(0, "")}
<< {conversationId: 1, payload: BinData(0,""), done: true, ok: 1}
RTT was improved with MongoDB 4.4+ as 2 round trips can potentially be avoided:
- when
speculativeAuthenticate
is used thesaslStart
command is incorporated into the initial MongoDB handshake - when the
saslStart
command contains theskipEmptyExchange: true
option, the secondsaslContinue
command can be skipped
1
2
3
4
5
6
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 2 // TLS
+ 1 // MongoDB
+ [2 , 3] // Authentication
Reducing Round Trips
As outlined above there are a number of network round trips required to authenticate a client connection to a MongoDB host using a username and password:
1
2
3
4
5
6
7
8
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 2 // TLS
+ 1 // MongoDB
+ [2 , 3] // Authentication
---------------------------
[6 , 10]
MongoDB 4.4 has been out since at least September 2020, so chances are most applications are connecting to at least this version or newer. This would put the average round trip count for authenticating a connection between 6 and 9 (depending on what protocol is being used and if DNS results were previously cached).
Next let’s review what can be done to reduce these round trips where possible.
Use x.509 Authentication
When using x.509 certificates to authenticate clients, the conversation with the server does not require a saslContinue
. Assuming this speculativeAuthenticate
of the initial handshake succeeds (which it should), two full round trip can be removed!
1
2
3
4
5
6
7
8
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 2 // TLS
+ 1 // MongoDB
+ 0 // Authentication
---------------------------
[4 , 7]
Note there’s no authentication round trips as the speculativeAuthenticate
succeeding contains the information typically sent via the saslStart
command.
Use TLS 1.3+
Source: thesslstore.com
TLS 1.3 (RFC 8446) can authenticate a connection approximately twice as fast as TLS 1.2 (RFC 5246) by eliminating a full round trip.
Though not necessarily supported (at time of writing) by the MongoDB Server, additional non-standard TLS 1.3 configurations can further help speed up encrypted connections - such as TLS false start and Zero Round Trip Time (0-RTT). See “TLS 1.3: Everything you need to know” for more information.
1
2
3
4
5
6
7
8
/* Network Round Trips */
[0 , 3] // Protocol
+ 1 // TCP
+ 1 // TLS
+ 1 // MongoDB
+ [0 , 3] // Authentication
---------------------------
[3 , 9]
Conclusion
In some environments (such as Function as a Service) the cold start time of an application is critically important. The time to authenticate a connection to a MongoDB host and how this can be improved can be useful in improving operational latency of applications.
Out of the box there may be upwards of 9 network round trips (SRV+TCP+TLS+MONGODB+AUTH
), however this can potentially be cut in half (or more) by understanding what configuration and authentication options exist and how they can be applied.
Comments powered by Disqus.