Random walk to my blog

my blog for sharing my knowledge,experience and viewpoint

0%

FMA故障模式介绍

微软的FMA(Failure Mode Analysis)设计方案, 将自动化的故障治理分为:

  • Detection: 故障探测,从直接指标上发现是否有某种类型的故障
  • Recovery: 故障恢复, 自动治理的过程,用于几时止损
  • Diagnostics: 故障定位, 一般由扔接入,排查故障根因,从本质上解决问题

以过载为例:

Detection对应排队时间超过10ms

Recovery对应自适应限流

Diagnostics对应根因定位,判断是上游有突增流量还是服务自身变更引入bug导致

FMA的梳理

Failure Detection Recovery Diagnostics
APP崩溃 服务进程不可用 自动挂起
用户非法调用接口,或者是用非法调用使系统过载 每次请求校验身份信息,并且将请求与用户ID绑定 - 对特定用户县里
- 封禁用户
服务更新引入bug 节点健康实时检查 回滚到是一个可用版本
后端节点建立连接失败 - 网络故障
- 后端服务未部署
- 授权失败
写Azure Search失败 在调用端捕获异常 重试
读Azure Search失败 在调用端捕获异常 重试
Curmos DB读写失败 在调用端捕获异常 - 重试
- 尽可能多副本部署DB
消息队列写入失败 - 本地缓存数据,消息队列可用后再写入
- 创建备用队列并且写入
消费者无法处理的某个特定信息 将消息发送到死信队列
读Redis失败 在调用端捕获异常 - 重试
- 缓存不命中,回源到DB
写Redis失败 在调用端捕获异常 - 重试
- 重试多次失败,暂时熔断,稍微写入缓存
SQL数据库建立连接失败 监控连接失败异常 前提是DB在多地区部署
- 读请求,自动化切换到副本
- 写请求,需要人工切换到副本
SQL客户端使用完所有连接池的连接 监控失败连接异常 - 重试
- 客户端做连接池隔离
- 增加连接池上限
数据库连接池达到上限 - 调用端捕获异常
- 监控特定的错误码
一般是瞬时的故障,即可以通过重试解决。如果持续命中这样的错误,意味着DB需要扩容
Service Bus(消息队列管理)读失败 SDK侧捕捉异常,并且标识异常是否为瞬时的 - 重试
- 重试几次还是失败后,将消息写入死信队列
Service Bus(消息队列管理)写失败 SDK侧捕捉异常,并且标识异常是否为瞬时的 - 重试
- 如果写失败为:队列quota用完,则需要排空队列的部分消息。调用端熔断
- 尽可能地使用分区队列或者Topic
- 消费双发
Service Bus处理重复消息 检测ID和发送的数量 - 尽量将消费的流程做到幂等,否则需要在消息消费前识别消息ID,判断是否消费过
- Service Bus检查消息ID,在一定事件窗口内,只会将不重复ID的消息放入消息队列
通过日志检查
Service Bus消费侧对于特定消息处理失败 业务强相关场景,比如消息出现无效字段 - 直接将消息移动到死信队列,之后执行独立的逻辑来检测死信队列
- [Peek Lock模式] 用于消费者内部逻辑异常的情况(例如panic等),这是给消息加锁,锁过期后,再次处理消息,如果达到最大加锁次数,或者超过一定时间,将消息移入死信队列
有消息进入死信队列,发送一个事件
服务调用失败 下游服务返回error 1.重试
2.有状态的服务做逻辑上的回滚
3.无状态服务保证处理的幂等性
4.错误率很高的需要熔断
应用日志

从以上表格看到,最通用的手段是重试,其次是熔断。

瞬时故障与非瞬时故障

  • 首先基于下游错误码来判断是瞬时还是非瞬时
  • 瞬时故障可以有限通过重试机制解决
  • 重试超过次数没有成功,则将故障判定为非瞬时
  • 非瞬时故障的处理与瞬时逻辑不同,一般有:熔断,切流,移入死信队列等

DB容灾

对DB容灾有特有的主备切换能力,其中读接口实现了自动切换,但是写接口需要人工手动切换。

写切主,需要考虑主备同步的问题。一般操作流程是,关闭写接口,等待写接口流量掉0,且主备数据完全同步之后,在切主,最后开放写接口

MQ容灾

缓存后写入

MQ写入失败后,Azure的做法是将数据缓存在本地,先给客户端返回成功,再异步地讲缓存数据写入MQ直到成功(如果一直没有成功会放入死信队列)。

这种做法将数据缓存在本地,会有实例重启/迁移导致数据丢失的风险,更保险的做法是将数据缓存在Redis。

死信队列

如果一个消息一直无法被消费,需要有个停止的方式,一般放在死信队列。

主备切换

为了应对写MQ故障,Azure

  • 被动双发。写入主消息队列的错误率超过阈值后,切换写入到备消息队列
  • 主动双发。同时将消息写入主备消息队列
  • 消费侧做法。上述两种方式,消费者都要同时监听2个队列,并且需要针对消息做去重。