Worker threads vs shared SSL_CTX: handshake latency under concurrent TLS load
0 reputation · 02 Aug 2024, 17:10 UTC
0 reputation · 02 Aug 2024, 17:10 UTC
A design is being evaluated where an application uses worker threads with libssl/libcrypto, a single process-wide SSL_CTX for configuration, and a separate SSL object per network connection. The goal is to keep TLS configuration immutable and shared while connection state remains per-connection.
OpenSSL 1.1.0+ documents thread safety around the split between shared configuration in SSL_CTX and mutable per-connection state in SSL. The unresolved behavior concerns shared mutable subsystems that are part of the context: server session cache, session ticket keys, OCSP stapling updates, randomness, and OpenSSL 3.x provider and EVP algorithm resolution. These are part of the integration boundary between the application worker model and libssl.
The decision point is whether a single SSL_CTX with per-thread SSL objects is sufficient for concurrent handshakes, or whether per-worker SSL_CTX instances are needed to isolate caches, tickets, and provider state at the cost of memory and duplicated session reuse.
Is session cache and ticket key state inside SSL_CTX contended under concurrent handshakes? Does OpenSSL 3.x provider and EVP fetch introduce per-handshake lookup cost when using a shared context? Should session resumption policy be treated as part of the TLS integration boundary between workers and libssl?
31775 reputation · 03 Aug 2024, 01:50 UTC
For concurrent TLS handshakes, a single SSL_CTX with per-thread SSL objects is functionally sufficient and the standard design. However, under high concurrent load, the internal session cache, ticket-key callbacks, and OCSP stapling mechanisms are protected by a single mutex. This lock becomes a measurable bottleneck when handshake rates reach high thresholds (typically >10k/s) on multi-core systems. Per-worker SSL_CTX instances eliminate this lock contention but disable cross-worker session resumption and increase memory overhead due to duplicated certificate chains and caches.
SSL_CTX lock.RAND_bytes calls are lock-free after initial seeding because OpenSSL 1.1.1+ uses per-thread DRBG instances.SSL_CTX instances duplicate the X509_STORE, certificate chains, and DH parameters, typically costing 200–500 KiB per instance plus cache memory.Latency spikes under concurrent load are usually caused by mutex contention rather than algorithm computation. When multiple threads attempt to validate or store sessions simultaneously, they queue for the SSL_CTX lock. This effect is severely amplified if ticket-key or OCSP callbacks perform blocking I/O (such as calling an HSM or network service), as the lock is held for the duration of the call, effectively serializing all handshakes across the process.
In contrast, OpenSSL 3.x provider fetches are a "warm-up" cost. Once the required EVP algorithms (e.g., AES-GCM) are fetched and reference-counted, they do not contribute to per-handshake latency.
SSL_CTXSSL_CTX is NecessarySSL_CTX cache redundant.openssl s_server -www -multi N and openssl s_time -connect ... -new with varying thread counts (1, 2, 4, 8) to identify the saturation point.perf lock record to determine if CRYPTO_THREAD_lock or similar mutexes are the primary source of CPU wait time.openssl version -v to ensure you are using 1.1.1k+ or 3.0.8+ to benefit from known lock optimizations.export OSSL_TRACE=PROVIDER to confirm that algorithm fetches occur only during initialization.To provide a definitive recommendation, what is the expected peak number of concurrent TLS handshakes per second the application must support?
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.