Overview
TLS Session Reuse
11 min
introduction for low latency applications, every millisecond counts one common source of unnecessary latency is the repeated tls handshake process when making api requests if your application does not reuse tls sessions, it incurs extra latency and computational overhead for every new connection to mitigate this, we strongly recommend implementing tls session reuse and connection pooling this guide explains these concepts and provides examples in java, python, and node js understanding tls session reuse what happens without tls session reuse? your client initiates a connection to our api a full tls handshake occurs, which requires multiple round trips the handshake establishes a secure connection, but if not reused, a new handshake will be required for subsequent connections how tls session reuse helps reduces handshake latency by reusing an existing tls session, your client avoids repeating the costly handshake process lowers cpu and memory usage each handshake requires cryptographic operations that consume resources improves request throughput persistent connections reduce the overhead of setting up new tls sessions to achieve this, use connection pooling and enable persistent connections in your http client debugging tls handshake time with curl to check your api request's tls handshake time, use curl o /dev/null s w " dns lookup %{time namelookup}s tcp connect %{time connect}s tls handshake %{time appconnect}s pre transfer %{time pretransfer}s start transfer %{time starttransfer}s total time %{time total}s " https //api forter secure com this will output dns lookup 0 388898s tcp connect 0 529150s tls handshake 0 975320s pre transfer 0 975733s start transfer 1 119405s total time 1 120284s tls handshake indicates how long it took for the tls handshake to happen notice at the above request it took 450 milliseconds if tls handshake is consistently high, your client might not be reusing tls sessions implementing tls session reuse java example (using apache httpclient) package org forter tlsreuseexample; import org apache hc client5 http classic methods httpget; import org apache hc client5 http impl classic closeablehttpclient; import org apache hc client5 http impl classic httpclients; import org apache hc client5 http protocol httpclientcontext; import org apache hc core5 http classichttpresponse; import org apache hc core5 http io entity entityutils; import org apache hc core5 util timevalue; import java io ioexception; import java net urisyntaxexception; import java util hexformat; public class main { public static void main(string\[] args) throws exception { httpget request = new httpget("https //api forter secure com"); var clientcontext = httpclientcontext create(); system out println("====== using 0 keep alive w/o connection reuse configuration ========"); try (closeablehttpclient client = httpclients custom() setconnectionreusestrategy((request1, response, context) > false) setkeepalivestrategy((response, context) > timevalue ofmilliseconds(0)) build()) { executerequest(request, client, clientcontext); } system out println("====== using regular pool configuration ========"); try (closeablehttpclient client = httpclients createdefault()) { executerequest(request, client, clientcontext); } } private static void executerequest(httpget request, closeablehttpclient client, httpclientcontext clientcontext) throws urisyntaxexception, ioexception, interruptedexception { system out println("sending request to " + request geturi()); client execute(request, clientcontext, response > consumeresponse(response, clientcontext)); thread sleep(100); system out println("=====================\n"); system out println("sending request to " + request geturi()); client execute(request, clientcontext, response > consumeresponse(response, clientcontext)); system out println("=====================\n"); } private static object consumeresponse(classichttpresponse response, httpclientcontext clientcontext) throws ioexception { entityutils consume(response getentity()); var sslsession = clientcontext getsslsession(); sslsession invalidate(); string sessionidhex = hexformat of() formathex(sslsession getid()); system out println("ssl session id " + sessionidhex); response close(); return null; } } uses connection pooling to maintain persistent connections reuses tls sessions to minimize handshake overhead notice the output from the above program looks like this, you can see that the ssl session id is the same on the 2nd run, where default pool configuration is used, which uses keepalive and connection reuse \====== using 0 keep alive w/o connection reuse configuration ======== sending request to https //api forter secure com/ ssl session id 7f60fd646dd1239a9210ad844c4a3e81317e3780dc9b39aaeffd3160c69d99c6 \===================== sending request to https //api forter secure com/ ssl session id 8df20ed84d6128dd560ccc4abbcd58fb1185198fcae5e23b979d57cba64ca92e \===================== \====== using regular pool configuration ======== sending request to https //api forter secure com/ ssl session id 48ab1d57adb15c810cac201d9576475b29bb0f8875838c1de0c94e53e740fe6f \===================== sending request to https //api forter secure com/ ssl session id 48ab1d57adb15c810cac201d9576475b29bb0f8875838c1de0c94e53e740fe6f \===================== python example (using requests session) note that when using python requests library “session”, it automatically does keepalive https //requests readthedocs io/en/latest/user/advanced/#keep alive and reuses the http connection import requests session = requests session() session get("https //api forter secure com") \# tls session reuse will happen here session get("https //api forter secure com") node js example (using https agent) const https = require("https"); const agent = new https agent({ keepalive true, // enables connection reuse maxsockets 10, // limits parallel connections maxfreesockets 5, }); https get("https //api forter secure com", { agent }, (res) => { console log(`status code ${res statuscode}`); }); // tls session reuse will happen here as the agent is reused https get("https //api forter secure com", { agent }, (res) => { console log(`status code ${res statuscode}`); }); enables keepalive to reuse tls sessions across requests limits open sockets to manage resource consumption effectively conclusion implementing tls session reuse and connection pooling significantly improves api performance by reducing handshake latency and optimizing resource usage use the provided examples to ensure your application efficiently reuses connections and minimizes unnecessary overhead