系统组件失效时的常见应对策略
如果遇到了网络,硬件,程序级别的组件失效,我们应该如何保证最小化影响呢?本文介绍了常见的技巧和策略。
- 大多数宕机源于系统变更:代码更新,配置变更等等。解决方案是变更先在一小部分实例中应用,通过监控,可以在有不良影响发生是快速回滚。
- 另一种方案是 blue-green / red-black 部署,部署两份,但负载均衡只指向其中一个,上线就是上到其中一个,然后让负载均衡切换到另一个。
- 应用提供
GET /health
之类的接口,或者其它自己报告的方法,告诉负载均衡自己的健康情况。负载均衡将其移除出 Pool Members,如果一个实例遇到了问题。 - Self Healing:可以开发一个系统,监控实例的健康,如果坏掉了,就自动将其启动。当然,我们要考虑程序过载,应用到数据库链接超时等等因素进来。需要引入额外的逻辑,知道当遇到什么情况的时候不要重启坏掉的实例。
- Failover Caching:相比服务挂掉什么都没了,如果可以接受返回过期数据,那就可以引入缓存组件。
- Retry: 当应用好了以后可以重试执行一些操作,不过要小心,它可能会引发层叠效应,让流量变得更多,让应用雪上加霜。重试,一般需要在客户端做,重试请求需要加上 idempotency-key 确保每个事务的唯一性。
- Rate Limiters and Load Shedders:给应用加上限流的装置,超出高峰后,直到 autoscaling 完成之前销掉流量高峰。Load Shedder 则能确保一些核心事务能够有足够的资源对其进行处理。在限流的同时,让优先级高的请求通过予以执行。
- Fail Fast and Independently:比起请求 hang 在那里,不如尽快把请求掐掉,特别是在服务之间有不小的依赖链。给每个服务请求加上合适的 timeout。有人认为 timeout 是个反模式,更好地方法是加入熔断器(circuit breaker)
- Bulkhead:就像船舱会被设计成一个个隔离区域,就算破了一块区域,整艘船还能运行。我们可以将整体的流量细分,对每一份流量的流量设定请求连接上限。顺便一提,泰坦尼克号的 Bulkhead 设计缺陷在于,太多水进入了前部的船舱,导致失衡,船头扎入水中。
- 熔断器:引入一个计算请求成功和失败数量的组件,当超出阈值的时候,就开启熔断器,掐掉对整个应用的流量,避免引起整个系统的宕机。一般来说,熔断器过一段时间后会重新搭上。需要注意的是,像 4xx 这样的错误是客户端错误,不应处理,我们需要关注 5xx 这样的服务端错误。
- 测试失效:经常测试系统,可以引入 ChaosMonkey 这样的系统进行测试。
将服务稳定性从 99% 提升到 99.9999% 需要付出非常多的人力和财力!