Search code examples
sslgotcptls1.2

How to cache/reuse TLS connections in Go


I've run into a problem where I create a new connection each request and it is terribly inefficient.

I would like to allow a set maximum number of TLS connections to stay open/cached on my client at once. When data is ready to be transmitted it first checks if there is an idle connection, then it checks if it can create a new connection (i.e. number of open connections < maximum allowed). If both are false then it has to wait until either a connection becomes idle or the number of open connections decreases. Connections should also be killed after they have been idle for a set amount of time.

Here is some (bad) pseudocode of what I have in mind. Could I have some suggestions?

func newTLSConnection(netDialer, host, tlsConfig) (tls.Con) {

    // Set up the certs
    // ...

    // Make A TLS Connection
    con, _ := tls.DialWithDialer(netDialer, "tcp", host, tlsConfig)

    return con
}

func (con tls.Con) Do (someData []byte) {

    // If con 
    // Send some date to the server
    _, _ := con.Write(someData)

    // Get response from server
    response := make([]byte, 100)
    _, _ := io.ReadFull(con, response)

    return
}


main(){
    var cons []tls.Con
    maxConSize := 3

    while {

        if allConsInSliceAreBusy() && len(cons) < maxConSize{
            newCon = NewTLSConnection(...)
            cons = append(cons, newCon)
            conToUse := newCon

            conToUse.Do([]byte("stuff"))

        } else if !allConsInSliceAreBusy() {

            conToUse := firstOpenConInCons()

            conToUse.Do([]byte("stuff"))

        } else{
             // NOP. Max cons created and they are all busy.
             // Wait for one to become idle or close.
        }
    }
}

Thank you!


Solution

  • What you ask about is called connection pooling. Have a look at Fasthttp package source code: https://github.com/valyala/fasthttp/blob/master/client.go. You can even use this library or another one for your purpose.

    You can find the acquireConn func which does exactly what you need:

    • Locks connection pool to allow concurrent execution.
    • Creates new connections if pool is empty (new connections are pulled out of the pool).
    • Makes connections cleanup in case of TTL timeout.