实际需要的 ssl_session_cache 大小应按公式 cache_size ≈ new_sessions_per_sec × timeout_sec × 0.5KB 计算,例如 800 新会话/秒、4h 超时需约 6MB,建议起步配 shared:SSL:10m;必须统一配置在 http 块顶层且仅一次,否则可能引发未定义行为;溢出无报错但会导致全握手,可通过日志、stub_status 和 handshake 时间监控识别;务必同时启用 ssl_session_tickets 作为无状态补充,并保留 shared 缓存作 fallback。

共享内存大小不能靠猜,必须按每秒新会话数 × 会话存活时间 × 单条开销来算;10m 是默认值,不是推荐值。
怎么算出实际需要的 ssl_session_cache 大小
核心公式是:cache_size ≈ new_sessions_per_sec × timeout_sec × 0.5KB。其中:
-
new_sessions_per_sec不是 QPS,而是「每秒新建 TLS 会话数」,可通过openssl s_client -connect example.com:443 -reconnect持续压测 +nginx -s reload后观察日志中$ssl_session_reused字段统计得出(0表示全握手) -
timeout_sec对应配置中的ssl_session_timeout,建议设为4h(即 14400 秒),过短会导致复用率断崖下跌 -
0.5KB是保守估算值,实际单条占用在 256–512 字节之间,取决于证书链长度、TLS 版本(TLSv1.3 PSK 条目略小)和是否启用 OCSP stapling
举例:若实测峰值每秒新建 800 个会话,ssl_session_timeout 4h,则需约 800 × 14400 × 0.5 / 1024 ≈ 5625KB ≈ 6MB;但为留余量,建议直接配 shared:SSL:10m 起步,高并发场景(如 >2000 新会话/秒)应上 20m 或更高。
为什么 ssl_session_cache shared 配在 http 块顶层才有效
多个 server 块里重复写 ssl_session_cache shared:SSL:10m,Nginx 会合并成同一块共享内存区,但存在风险:
- 若某
server块中误写成shared:SSL:5m,可能触发未定义行为,尤其在 reload 时 - Worker 进程只认主进程初始化的那一份共享区,
server级配置无法改变其生命周期或锁机制 - 真正生效的只有 http 块中首次声明的那一条;其余同名声明会被忽略或覆盖,不报错也不提示
所以务必统一写在 http 块开头附近,且只出现一次。验证方式:运行 nginx -T | grep "ssl_session_cache.*shared",输出应仅一行,且位置在 http { 之后、任何 server { 之前。
如何确认共享内存真的没溢出
溢出不会报错,但会静默退化为全握手——表现为 CPU 突升、延迟变高、$ssl_session_reused 日志中 .0 比例明显上升。可用这些方法交叉验证:
- 用
kill -USR1 $(cat /var/run/nginx.pid)触发主进程打印共享内存统计(需提前开启error_log /var/log/nginx/error.log debug;);搜索日志中SSL缓存行,看used:是否持续接近总大小 - 启用
stub_status模块后,对比Active connections和Accepts的增速差:若 Accepts 暴涨而 Active 增长缓慢,说明大量连接卡在握手阶段 - 监控
ssl_handshake_time的 P95 值:稳定在 10–30ms 是复用正常;若频繁跳到 80–200ms,大概率已开始全握手
注意:Windows 平台无法使用 shared 模式,builtin 模式下每个 Worker 自维护缓存,不存在“溢出”概念,但复用率随 Worker 数线性下降——这是架构限制,不是配置问题。
要不要启用 ssl_session_tickets 作为补充
要,而且建议强制开启:
-
ssl_session_cache是服务端有状态缓存,受内存限制;ssl_session_tickets是服务端加密后下发给客户端存储的会话信息,服务端无状态,不占共享内存 - 配置只需两行:
ssl_session_tickets on;+ssl_session_ticket_key /etc/nginx/ticket.key;(密钥文件需 48 字节随机二进制,定期轮换) - 它对 TLSv1.2 客户端效果显著,对 TLSv1.3 客户端则是必选项(PSK 主要靠 ticket 实现)
- 唯一代价是首次握手多传几百字节 ticket 数据,但远小于全握手的开销
真正容易被忽略的是:即使启用了 ssl_session_tickets,仍需保留 ssl_session_cache shared。因为 ticket 机制依赖服务端能解密并验证 ticket,而 ticket key 变更或节点重启时,旧 ticket 会失效,此时 fallback 到 session ID 复用就靠共享缓存兜底。


















