I
Editorial
证书临期轮换本该是例行操作,线上却出现「部分实例间歇 SSL handshake failure / certificate verify failed」——重启应用就好,过一会又来。这类问题经常不是证书文件本身坏了,而是连接池、长连接与多进程缓存了旧 TLS 会话或旧 CA/证书路径。本帖按常见反向代理 + 应用连接池场景整理排查顺序。
一、先对齐故障边界
1. 失败是集中在轮换后数分钟/数小时,还是随机全天:前者高度怀疑池内旧连接;后者先查时钟、CA 包、SNI。
2. 看是客户端校验失败还是服务端拒:两边日志的 alert 描述不同,别只看网关 5xx。
3. 多副本是否只有部分中招:说明有的进程热加载成功、有的仍握着旧 fd 或旧内存证书。
二、连接池与长连接
1. HTTP 连接池(应用侧)在证书切换后仍复用旧 TCP/TLS 会话时,会把错误「延迟」到下一次读写;短 TTL 或强制在密钥轮换时 drain 池,比盲目加大超时更有效。
2. 反向代理 upstream keepalive:轮换上游证书时,应显式把旧 upstream 连接关掉再接新证。
3. gRPC / HTTP2 多路复用:一条坏连接可以拖一串 RPC;观察是否与 GOAWAY/连接年龄相关。
4. 会话票据/会话缓存:客户端 session resumption 碰到服务端新证时行为因栈而异,轮换窗口可临时关闭 ticket 做对照。
三、证书与信任链
1. 确认热加载路径读到的是新文件:inode 替换 vs 同 inode truncate,不同运行时行为不同。
2. 中间证书是否一并更新;缺链时部分客户端严格校验失败、部分宽松通过,表现为「只有某语言栈挂」。
3. 时钟与 OCSP/CRL:轮换窗口若碰上时间偏移,会放大成「随机失败」。
四、变更与演练
1. 轮换 runbook:先发新证(双证并存)→ drain 连接 → 撤旧证;不要「同一秒替换 + 期望池自己好」。
2. 预发环境用长连接压测打满池,再做轮换,看失败曲线。
3. 指标:握手失败率、连接年龄直方图、池内空闲连接数,和证书 notAfter 放同一仪表盘。
五、常见误区
- 只重启一台「好了」就结案,不查池化复用。
- 应用与代理各管各的证书,轮换不同步。
- 把 verify 关掉当临时方案留在生产。
欢迎分享你们在 Envoy/Nginx、语言运行时连接池、以及 mTLS 双向轮换上的坑。
一、先对齐故障边界
1. 失败是集中在轮换后数分钟/数小时,还是随机全天:前者高度怀疑池内旧连接;后者先查时钟、CA 包、SNI。
2. 看是客户端校验失败还是服务端拒:两边日志的 alert 描述不同,别只看网关 5xx。
3. 多副本是否只有部分中招:说明有的进程热加载成功、有的仍握着旧 fd 或旧内存证书。
二、连接池与长连接
1. HTTP 连接池(应用侧)在证书切换后仍复用旧 TCP/TLS 会话时,会把错误「延迟」到下一次读写;短 TTL 或强制在密钥轮换时 drain 池,比盲目加大超时更有效。
2. 反向代理 upstream keepalive:轮换上游证书时,应显式把旧 upstream 连接关掉再接新证。
3. gRPC / HTTP2 多路复用:一条坏连接可以拖一串 RPC;观察是否与 GOAWAY/连接年龄相关。
4. 会话票据/会话缓存:客户端 session resumption 碰到服务端新证时行为因栈而异,轮换窗口可临时关闭 ticket 做对照。
三、证书与信任链
1. 确认热加载路径读到的是新文件:inode 替换 vs 同 inode truncate,不同运行时行为不同。
2. 中间证书是否一并更新;缺链时部分客户端严格校验失败、部分宽松通过,表现为「只有某语言栈挂」。
3. 时钟与 OCSP/CRL:轮换窗口若碰上时间偏移,会放大成「随机失败」。
四、变更与演练
1. 轮换 runbook:先发新证(双证并存)→ drain 连接 → 撤旧证;不要「同一秒替换 + 期望池自己好」。
2. 预发环境用长连接压测打满池,再做轮换,看失败曲线。
3. 指标:握手失败率、连接年龄直方图、池内空闲连接数,和证书 notAfter 放同一仪表盘。
五、常见误区
- 只重启一台「好了」就结案,不查池化复用。
- 应用与代理各管各的证书,轮换不同步。
- 把 verify 关掉当临时方案留在生产。
欢迎分享你们在 Envoy/Nginx、语言运行时连接池、以及 mTLS 双向轮换上的坑。