第2章 容错设计基本原则:优雅降级、幂等性、原子性、超时与重试机制、熔断与限流在密码改造中的应用

做密码改造这几年,我最大的感受就是:再完美的改造方案也扛不住网络抖动、服务雪崩和人为失误。你想想看,加密机突然挂了、密钥库连接超时、老系统缓存了旧加密结果——哪一样都让人头疼。所以这一章我重点聊聊容错设计的五个基本功:优雅降级、幂等性、原子性、超时与重试、熔断与限流。这五个东西我用在了密码改造的每个环节,效果还不错。

核心观点:容错不是兜底方案,而是改造上线前就必须设计进去的工程习惯。
密码改造容错设计原则 改造容错 优雅降级 降密级+降功能 幂等性 去重+防重复 原子性 全成功或全回滚 超时与重试 限时+指数退避 熔断与限流 断开关+降流量

优雅降级

说白了就是系统扛不住了,先给用户一个保底的加密服务。比如核心加密机超时,不要直接甩500,而是临时切到本地缓存密钥做一次降级签名,虽然强度低了点,但业务还能跑。我在改造一个支付系统时遇到过,上游加密服务挂了,结果下游所有交易报错。后来我加了一层降级开关:默认走硬件加密,失败后降级为软件加密(纯CPU算,但允许业务继续)。

  • 降级要分等级:L1正常→L2降密级(比如从SM4降为AES-128,但业务能接受)→L3降功能(只返回缓存结果)
  • 必须设置降级阈值:连续失败3次才触发,避免误判
  • 降级后要自动尝试恢复,别一直卡在低水位
我曾经踩过的坑:降级策略没配恢复窗口,结果加密机恢复了还在用低安全方案运行了一个月。记得加一个定时探测,每隔5分钟试一次原路。

幂等性

密码改造里最容易被忽略的就是幂等。举个例子:加密请求因为网络超时,客户端重试了一次,结果密文多存了一份,业务对账对不上。我习惯在请求里带一个全局唯一ID(例如reqId),服务端收到先查表,如果ID已存在且结果相同,直接返回旧结果,不再重复执行加密。

// 幂等处理伪代码
if redis.exists(reqId):
    return redis.get(reqId)  // 直接返回之前的结果
else:
    ciphertext = encrypt(plaintext, key)
    redis.setex(reqId, ciphertext, 86400) // 存储一天
    return ciphertext
一个小技巧:幂等键的过期时间别设太短,至少覆盖重试窗口+业务处理时间。我通常设24小时,避免半夜跑批时幂等失效。

你想想看,如果一次加密操作被重试了5次,每次都要重新生成密钥,那密钥管理系统迟早被拖垮。幂等既是容错,也是省钱。

原子性

密码改造经常涉及多步操作:更新密钥、加密数据、更新元数据。这三步必须要么全做,要么都不做。我见过一个事故:密钥更新成功,但数据加密了一半服务挂了,结果新密钥下既有旧密文也有新密文,恢复时根本分不清。原子性可以用本地事务或分布式事务保证,但密码改造场景我更推荐“先写日志再执行”的模式。

  1. 在数据库里插入一条操作日志(状态:待执行)
  2. 执行加密/密钥变更操作
  3. 更新日志状态为成功(或失败)
  4. 如果第2步失败,回滚:比如删除新密钥,或者恢复旧备份
原子性的核心:每个操作都要有明确的回滚脚本。我写改造代码前,必先把回滚SQL写好。

超时与重试机制

密码服务对外部依赖很敏感,比如调用KMS(密钥管理服务)或者HSM(硬件安全模块),响应时间通常不可控。我建议每个外部调用都要设置超时,并且区分读和写:读操作超时短(比如2秒),写操作稍微长点(5秒),但绝不能无限等。

操作类型推荐超时重试策略最大重试次数
读取密钥2s立即重试一次+指数退避3
加密/解密5s指数退避(1s 2s 4s)3
密钥生成10s不重试(幂等性靠请求ID保证)0
切记:重试不是无脑重复。我记得有一次生产事故,重试策略没做退避,3秒内重试了50次,直接把加密机打趴了。一定要加上退避和抖动(jitter),分散请求压力。

熔断与限流

熔断和限流是一对好兄弟,一个保护上游,一个保护下游。在密码改造中,熔断通常用在调用下游加密服务时——如果连续10次超时或报错,就打开熔断开关,直接返回降级结果,不再请求下游。限流则管住自己:比如每秒最多处理1000次加密请求,超过的直接返回429,防止把CPU和内存耗尽。

我一般结合实现:用滑动窗口统计失败率,达到阈值就熔断30秒。30秒后进入半开状态,试探一个请求,如果成功则关闭熔断,否则继续熔断。

我的习惯:熔断不要和重试过度耦合。比如熔断期间,外部重试请求直接返回失败,不消耗熔断次数。否则会陷入“熔断-重试-熔断关闭-重试”的死循环。

这五个原则在密码改造中不是孤立用的。比如一次加密请求:先限流挡住洪峰→设置超时→超时后重试两次(带退避)→重试失败触发熔断→熔断打开后走优雅降级→降级过程中保持幂等性和原子性。你想想看,这套组合拳下来,系统是不是稳多了?

一句话总结:密码改造的容错,不是等出了问题再修,而是用这些原则把问题消灭在发生的那一刻。