如何利用PHP微服务降低HTTPS的TLS握手开销?
Great question—when you're dealing with a high-throughput main service hitting 5 microservices per request, TLS handshake overhead can quickly become a bottleneck, even after optimizing your application code. Here are the most practical, production-proven fixes I’ve implemented or seen work:
1. 启用TLS会话复用(Session Resumption)
This is the low-hanging fruit. TLS handshakes are expensive because of the public key cryptography steps, but session reuse lets you skip most of that for repeat connections. There are two main methods:
- Session IDs: The server stores session state in a cache, and the client sends the ID on subsequent requests to resume the session. Configure your microservices' servers (e.g., Nginx, Tomcat) to enable shared session caching—for Nginx, add
ssl_session_cache shared:SSL:10m;to your config. - Session Tickets: Instead of the server storing state, it encrypts session data and sends it to the client to hold. This is better for scaled-out microservices since you don’t need a shared cache across instances. Enable with
ssl_session_tickets on;(Nginx) or equivalent in your server stack.
Make sure your main service (acting as the TLS client) is configured to support both methods—most modern HTTP clients (like OkHttp, Apache HttpClient) do this by default, but double-check your settings.
2. 升级到HTTP/2(或HTTP/3)
HTTP/2 was built to fix exactly this kind of problem. It supports multiplexing, meaning multiple requests can be sent over a single TLS connection. Instead of opening a new connection (and doing a full handshake) for each sub-request to a microservice, your main service can maintain a small pool of persistent connections to each microservice, and send all sub-requests over those connections.
HTTP/3 (based on QUIC) takes this further with faster handshakes (even 0-RTT in some cases) and better connection resilience, but HTTP/2 is easier to adopt since most modern servers and clients support it out of the box. Just ensure both your main service and microservices are configured to use HTTP/2 over TLS.
3. 优化长连接(Keep-Alive)配置
Even without HTTP/2, keeping TLS connections open for longer can drastically reduce handshake frequency. Adjust the keep-alive timeout on both client (main service) and server (microservices) sides to match your request patterns:
- For servers, set a reasonable timeout (e.g.,
keepalive_timeout 65s;in Nginx) so connections stay open long enough to handle multiple requests from the main service. - On the client side, configure your HTTP client to reuse connections (e.g.,
Connection: keep-aliveheaders, and a connection pool that doesn’t discard connections immediately).
4. 启用TLS 1.3的0-RTT Resumption(如果业务允许)
TLS 1.3 introduced 0-RTT resumption, which lets the client send application data before receiving the server’s response to the handshake. This cuts handshake latency to near-zero for repeat requests. However, there’s a minor security trade-off (risk of replay attacks), so only enable this if your microservices’ endpoints are idempotent or you can mitigate the risk. Most modern server stacks support TLS 1.3—just make sure both client and server are configured to use it.
5. 考虑请求合并或服务聚合(业务允许的话)
If your microservices handle related data, you could build an aggregator service that your main service calls once, instead of calling 5 separate services. The aggregator would then fan out to the microservices internally (possibly using faster internal communication, like gRPC with HTTP/2). This reduces the number of TLS handshakes per main request from 5 to 1, which can be a huge win if your business logic allows it.
6. 内部网络TLS优化(私有环境专属)
If all your services are running in a trusted private network (like a Kubernetes cluster or VPC), you can optimize TLS without sacrificing security:
- Use gRPC with TLS 1.3—it’s designed for high-performance service-to-service communication, with built-in connection pooling and multiplexing.
- Consider service mesh tools like Istio or Linkerd, which handle mTLS between services automatically, optimize connection reuse, and can even offload TLS processing to sidecars, reducing overhead on your main service.
- In some cases, you might even use plain HTTP internally with network-level encryption (like IPsec), but only if you’re 100% confident in your network’s security.
For most cases, combining session reuse + HTTP/2 + optimized keep-alives will give you the biggest performance boost with minimal effort. If you’re using container orchestration, service meshes can automate a lot of these optimizations so you don’t have to tweak each service’s config individually.
内容的提问来源于stack exchange,提问作者nemenems

