Nginx 1.19.4+ 可用 $ssl_handshake_time 统计成功 HTTPS 握手耗时(微秒级),需结合 log_format 按 IP、域名、协议等维度分析,注意其不覆盖失败、超时及会话复用场景。

直接利用 Nginx 自带的 $ssl_handshake_time 变量,配合 access_log 格式定制,就能在不改代码、不装插件的前提下,按客户端 IP、域名、协议等维度统计 SSL 握手耗时。这是最轻量、最通用、也最容易落地的监控方式。
启用并验证 $ssl_handshake_time 可用性
该变量从 Nginx 1.19.4 起正式支持,仅在 HTTPS 请求成功完成握手后才被赋值(单位:秒,精确到微秒),失败或跳过握手(如会话复用)时为空。确认方法:
- 运行
nginx -v检查版本 ≥ 1.19.4;若为 OpenResty,需 ≥ 1.21.4.2 - 在 server 块中添加测试日志:
log_format debug_ssl '$remote_addr - $ssl_handshake_time $ssl_protocol $ssl_cipher'; - 重启后访问一次 HTTPS 页面,检查
/var/log/nginx/access.log是否出现类似203.0.113.5 - 0.028345 TLSv1.3 TLS_AES_256_GCM_SHA384的记录
按客户端 IP 统计握手延迟分布
将耗时与源 IP 关联,可快速识别区域性弱网或异常设备。推荐配置如下:
log_format ssl_by_ip '[$time_local] $remote_addr $ssl_handshake_time $ssl_protocol $request_time';
随后用 shell 快速分析(例如取最近 1 万条):
- 查看平均/最大耗时:
awk '{sum += $3; if ($3 > max) max = $3} END {print "avg:", sum/NR, "max:", max}' /var/log/nginx/access.log | tail -10000 - 筛选慢握手(>500ms)并去重 IP:
awk '$3 > 0.5 {print $2}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20 - 结合时间窗口看趋势:
awk -F'[][]' '$2 ~ /May 13 10:/ {print $3}' /var/log/nginx/access.log | awk '{print $2}' | sort | uniq -c
按域名与协议拆解性能差异
多站点共用 Nginx 时,不同域名可能使用不同证书链或 TLS 配置,导致握手表现分化。建议在 log_format 中加入关键标识:
log_format ssl_breakdown '$host $ssl_protocol $ssl_ciphers $ssl_handshake_time $upstream_http_content_type';
这样可分别统计:
- TLS 版本影响:对比
TLSv1.2与TLSv1.3的平均握手时间,验证升级收益 - 证书链长度:若某域名频繁出现高耗时且
$ssl_ciphers显示 ECDHE-RSA 而非 ECDHE-ECDSA,可能因 RSA 签名验签慢 - OCSP Stapling 效果:开启
ssl_stapling on后,观察对应域名的$ssl_handshake_time是否显著下降(尤其对移动客户端)
规避常见误读与盲区
$ssl_handshake_time 不是万能指标,需注意其边界:
- 它只记录“成功完成握手”的耗时,不包含握手失败、超时断连、或会话复用场景——这些需靠 error_log 中
"ssl handshake timeout"或"SSL_do_handshake() failed"辅助判断 - 值为
-(短横)表示未发生完整握手,大概率是会话复用;若大量出现,说明缓存配置有效,但无法反映复用率本身——应配合$ssl_session_reused("s"/".")共同分析 - 该变量在
ssl_certificate_by_lua_block中不可用,如需更细粒度(如证书加载、OCSP 查询分段耗时),必须切换至 eBPF 或 OpenResty Lua 打点方案



















