可靠性与故障处理
复习
- 契约、错误与异常:明确地处理失败
- 日志与调试:保留现场,便于定位
- 从算法到软件:软件要长期使用
TL;DR
- 真实系统一定会出故障,要假设故障会发生
- 超时、重试、降级、恢复是常见手段
- 重试要小心:要有限度、要退避,并考虑重复执行的影响
- 目标不是“永不出错”,而是“出错也能撑住”
正文
软件要在真实世界里长期运行,就一定会遇到各种意外:网络断了、磁盘满了、依赖的服务挂了、流量突然暴涨。可靠性(reliability)要面对的,正是这些“一定会发生”的故障。
假设它会坏
可靠系统设计的第一条心态是:不要假设一切正常,而要假设故障迟早会发生。
如果某个操作可能永远卡住,就不能“一直等”;如果某个服务可能暂时不可用,就要想好“它挂了怎么办”。把故障当成常态来设计,系统才能在出问题时依然可用。
几种常见手段
应对故障,有几种常用手段:
- 超时:给操作设一个时限,别无限等待。卡住的操作,往往会拖垮整个系统
- 重试:暂时性失败,可以再试几次。但重试有讲究
- 降级:放弃次要功能,保住核心功能。比如推荐服务挂了,商品列表照常展示
- 恢复/熔断:把出问题的部分隔离、快速失败,避免故障扩散
重试要小心
重试看起来简单,其实暗藏陷阱。想想看:如果一个操作其实已经成功,只是确认没收到,你重试一次,会不会把同一件事做了两遍?
所以,重试要配合几件事:
- 有限度:不能无限重试,否则故障时反而雪上加霜
- 退避:每次重试间隔逐渐拉长,别一股脑猛冲
- 可重复执行:让操作“多执行一次也没关系”(幂等),重试才真正安全
这说明:处理故障的手段本身,也可能带来新问题。 可靠性设计,处处是这种需要细致权衡的地方。
目标:撑住,而不是不出错
可靠性的目标,从来不是“永不出错”——那不可能。真正的目标是:即使出了错,系统也能保持基本可用,并且能恢复。 这又回到了整部教程反复出现的那句话:没有绝对不出问题的系统,只有不断提高的可承受能力。
思考题 1
为什么可靠系统要“假设故障一定会发生”?
思考题 2
“重试”为什么需要小心设计?
小结
知识点
- 可靠系统假设故障必然发生
- 常见手段:超时、重试、降级、熔断与恢复
- 重试要有节制、退避,并考虑可重复执行
- 目标是故障时仍可用、可恢复
参考资料
- Wikipedia(zh):可靠性工程:提高系统可靠性的工程方法
- Wikipedia(zh):熔断器模式:故障时快速失败以避免扩散
思考题答案(仅供参考)
思考题 1
因为故障在真实环境中无法避免:网络会断、服务会挂、磁盘会满。只有把故障当作常态来设计(超时、降级、恢复等),才能在问题出现时保持可用,而不是一遇意外就整体崩溃。
思考题 2
因为盲目重试可能雪上加霜或造成重复执行:如果操作其实已成功、只是确认丢失,重试就会把同一件事做两遍;故障时无限重试还会加重系统负担。因此重试要有次数上限、采用退避,并尽量让操作可安全重复执行。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪