Connection handling and authentication in RavenDB 4.0
An interesting question has popped up in the mailing list about the behavior of RavenDB. When will RavenDB client send the certificate to the server for authentication? SSL handshake typically takes multiple round trips to negotiate an SSL connection, and that a certificate can be a fairly large object. It makes sense that understanding this aspect of RavenDB behavior is going to be important for users.
In the mailing list, I gave the following answer:
RavenDB doesn’t send the certificate on a per request basis, instead, it send the certificate at the start of each connection.
I was asked for a follow up, because I wasn’t clear to the user. This is a problem, I was answering from my perspective, which is quite different from the way that a RavenDB user from the outside will look at things. Therefor, this post, and hopefully a more complete way of explaining how it all works.
RavenDB uses X509 Client Certificates for authentication, using SSL to both authenticate the remote client to the server (and the server to the client, using PKI) and to ensure that the communication between client and server are private. RavenDB utilizes TLS 1.2 for the actual low level wire transfer protocol. Given that .NET Core doesn’t yet implement TLS 1.3 or FastOpen, that means that we need to do the full negotiation on each connection.
Now, what exactly is a connection in this regard? It this going to be every call to OpenSession? The answer is empathically not. RavenDB is managing a connection pool internally (actually, we are relying on the HttpClient’s pool to do that). This means that we are only ever going to have as many TCP connections to the server as you had concurrent requests. A session will effectively borrow a connection from the pool whenever it needs to talk to the server.
The connections in the pool are going to be re-used, potentially for a long time. This allow us to alleviate the cost of actually doing the TCP & SSL handshake and amortize it over many requests. This also means that the entire cost of authentication isn’t paid on a per request basis, but per connection. What actually happens is that on the beginning of the connection, the RavenDB server will validate the client certificate and remember what permissions are granted to it. Any and all requests on this connection can then just used the cached permissions for the lifetime of the connection. This stateful approach reduce the overall cost of authentication because we don’t need to run full validation on every request.
This also means that OpenSession, for example, is basically free. All it does is allocate a bunch of dictionaries and some other data structures for the session. There is no wire traffic because the session is created, only when you actually make a request to the server (Load, Query, SaveChanges, etc). Most of the time, we don’t need to create a new connection for that, but can use a pre-existing one from the pool. The entire system was explicitly designed to take advantage of best practices to optimize your overall performance.