用户抱怨"网站打开慢"。用 Chrome DevTools 分析发现,TTFB (Time To First Byte) 高达 400ms,其中 HTTPS 握手占了 200ms。这篇文章记录了将握手时间优化到 50ms 的全过程。
一、问题诊断
1.1 抓包分析
1
2
3
4
5
6
7
8
9
| # 使用 curl 测量各阶段耗时
curl -w "@curl-format.txt" -o /dev/null -s https://terra-nas.com
# curl-format.txt:
# time_namelookup: %{time_namelookup}s\n
# time_connect: %{time_connect}s\n
# time_appconnect: %{time_appconnect}s\n
# time_starttransfer: %{time_starttransfer}s\n
# time_total: %{time_total}s\n
|
结果:
1
2
3
4
5
| time_namelookup: 0.020s # DNS
time_connect: 0.060s # TCP (RTT ≈ 40ms)
time_appconnect: 0.260s # TLS 握手完成!
time_starttransfer: 0.280s
time_total: 0.350s
|
TLS 握手耗时 200ms,这是 TCP 连接后到应用数据传输的时间差。
1.2 握手耗时分解
使用 openssl s_client 详细分析:
1
| openssl s_client -connect terra-nas.com:443 -status 2>&1 | head -50
|
发现问题:
- 服务器使用 TLS 1.2(需要 2-RTT 握手)
- OCSP 响应客户端自己去查询(额外延迟)
- 证书链包含 3 个证书(传输量大)
二、TLS 握手原理
2.1 TLS 1.2 握手(2-RTT)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Client Server
| |
|------- ClientHello --------------->| RTT 1
|<------ ServerHello + Cert ---------|
|<------ ServerKeyExchange ----------|
|<------ ServerHelloDone ------------|
| |
|------- ClientKeyExchange --------->| RTT 2
|------- ChangeCipherSpec ---------->|
|------- Finished ------------------>|
|<------ ChangeCipherSpec -----------|
|<------ Finished -------------------|
| |
|======= Application Data ==========>| 终于可以发数据了!
|
耗时:至少 2 个 RTT,假设 RTT=40ms,则 TLS 握手 ≥ 80ms。
但我们测到 200ms,说明还有其他开销。
2.2 TLS 1.3 握手(1-RTT)
1
2
3
4
5
6
7
8
9
10
11
| Client Server
| |
|------- ClientHello + KeyShare ---->| RTT 1
|<------ ServerHello + KeyShare -----|
|<------ EncryptedExtensions --------|
|<------ Certificate ----------------|
|<------ CertificateVerify ----------|
|<------ Finished -------------------|
|------- Finished ------------------>|
| |
|======= Application Data ==========>| 1-RTT 后即可发数据!
|
优化点:ClientHello 直接携带密钥交换参数,减少一个 RTT。
2.3 0-RTT (TLS 1.3 Early Data)
1
2
3
4
5
6
7
8
| # 首次连接后,服务器发送 Session Ticket
# 后续连接可以直接发送加密数据
Client Server
| |
|------- ClientHello + EarlyData --->| 0-RTT!
|======= 应用数据已开始传输 ===========>|
|<------ ServerHello + ... ----------|
|
注意:0-RTT 有重放攻击风险,只适合幂等请求。
三、优化措施
3.1 启用 TLS 1.3
Nginx 配置:
1
2
3
4
5
6
7
8
9
10
11
12
| server {
listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.3; # 同时支持 1.2 和 1.3
ssl_prefer_server_ciphers off; # TLS 1.3 不需要这个
# TLS 1.3 密码套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
# 启用 0-RTT(注意安全风险)
ssl_early_data on;
}
|
效果:TLS 握手从 2-RTT 降到 1-RTT,节省 40ms。
3.2 OCSP Stapling
问题:客户端需要验证证书是否被吊销,传统方式是向 CA 发送 OCSP 请求。
1
2
3
4
5
| 传统方式:
Client --> Server: 获取证书
Client --> CA (OCSP): 证书有效吗? ← 额外 RTT!
CA --> Client: 有效
Client --> Server: 继续握手
|
OCSP Stapling:服务器预先获取 OCSP 响应,握手时一起发给客户端。
1
2
3
4
5
6
7
| ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
# 设置 OCSP 响应器
resolver 8.8.8.8 valid=300s;
resolver_timeout 5s;
|
验证:
1
2
| openssl s_client -connect terra-nas.com:443 -status 2>&1 | grep -A 15 "OCSP"
# OCSP Response Status: successful
|
效果:省去客户端 OCSP 查询,节省 50-100ms。
3.3 证书链优化
问题:完整证书链可能有 3-4 个证书,增加传输量。
1
2
3
4
5
| # 查看证书链
openssl s_client -connect terra-nas.com:443 -showcerts 2>/dev/null | grep "s:"
# s:/CN=terra-nas.com
# s:/CN=Let's Encrypt Authority X3 # 中间证书
# s:/CN=DST Root CA X3 # 根证书(不应该发送!)
|
优化:只发送网站证书 + 中间证书,不发根证书(浏览器已内置)。
1
2
3
4
5
6
7
| # 正确的证书文件应该是:
# 1. 网站证书
# 2. 中间证书
# (不包含根证书)
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
|
效果:减少 1KB 左右传输量。
3.4 Session Resumption
Session Ticket(无状态恢复):
1
2
3
4
5
| ssl_session_tickets on;
ssl_session_timeout 1d; # 24 小时有效
# 自定义 ticket key(多服务器需要共享)
ssl_session_ticket_key /path/to/ticket.key;
|
Session Cache(有状态恢复):
1
2
| ssl_session_cache shared:SSL:10m; # 10MB 共享缓存
ssl_session_timeout 1d;
|
效果:回访用户 TLS 握手降为 1-RTT 甚至 0-RTT。
3.5 使用 ECDSA 证书
RSA 证书签名验证较慢,ECDSA 更快且密钥更短。
1
2
3
4
5
6
7
8
| # 生成 ECDSA 私钥
openssl ecparam -genkey -name prime256v1 -out privkey.pem
# 生成 CSR
openssl req -new -key privkey.pem -out csr.pem
# 申请证书(Let's Encrypt 支持 ECDSA)
certbot certonly --csr csr.pem
|
对比:
| 类型 | 密钥长度 | 安全性等价 | 签名速度 |
|---|
| RSA 2048 | 2048 bits | 112 bits | 慢 |
| ECDSA P-256 | 256 bits | 128 bits | 快 3-4x |
3.6 启用 HTTP/2
HTTP/2 复用一个 TCP 连接,TLS 握手只需一次。
四、性能对比
4.1 优化前后测量
1
2
3
4
5
6
7
| # 优化前
curl -w "TLS: %{time_appconnect}s\n" -o /dev/null -s https://terra-nas.com
# TLS: 0.260s
# 优化后
curl -w "TLS: %{time_appconnect}s\n" -o /dev/null -s https://terra-nas.com
# TLS: 0.050s
|
4.2 耗时分解
| 优化项 | 节省时间 |
|---|
| TLS 1.3 (1-RTT) | 40ms |
| OCSP Stapling | 60ms |
| Session Resumption | 40ms |
| 证书链优化 | 10ms |
| ECDSA 证书 | 5ms |
| 总计 | ~150ms |
五、监控与验证
5.1 SSL Labs 测试
访问 https://www.ssllabs.com/ssltest/ 获取详细评分。
关注指标:
- Protocol Support: TLS 1.3 ✓
- OCSP Stapling: Yes ✓
- Certificate Chain: 2 certificates ✓
1
2
3
4
5
| Timing 面板:
DNS Lookup: 20ms
Initial connection: 50ms ← 大幅降低
SSL: 30ms ← TLS 握手
TTFB: 80ms
|
5.3 Prometheus 监控
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 监控 TLS 握手时间
- job_name: 'nginx'
metrics_path: '/metrics'
static_configs:
- targets: ['localhost:9113']
# 告警规则
- alert: HighTLSHandshakeTime
expr: nginx_http_ssl_handshake_time_seconds_bucket{le="0.1"} / nginx_http_ssl_handshake_time_seconds_count < 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "超过 10% 的 TLS 握手耗时 > 100ms"
|
六、完整配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| server {
listen 443 ssl http2;
server_name terra-nas.com;
# 证书
ssl_certificate /etc/letsencrypt/live/terra-nas.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/terra-nas.com/privkey.pem;
# 协议与密码套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/terra-nas.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# Session 复用
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
# 0-RTT (谨慎使用)
ssl_early_data on;
# 安全头
add_header Strict-Transport-Security "max-age=31536000" always;
# ...
}
|
七、总结
| 优化技术 | 原理 | 效果 |
|---|
| TLS 1.3 | 1-RTT 握手 | -40ms |
| OCSP Stapling | 服务器预取证书状态 | -60ms |
| Session Resumption | 复用之前的握手结果 | -40ms |
| 证书链精简 | 减少传输量 | -10ms |
| ECDSA 证书 | 更快的签名算法 | -5ms |
核心收获:HTTPS 性能优化不只是选择算法,更是减少往返次数 (RTT)。在高延迟网络(如跨国访问)中,这些优化效果更加明显。