熔断
熔断的目的是防止应用不断尝试可能会执行失败的操作,从而使得应用可以继续执行而不用等待异常情况的修复,或者浪费时间来等待长时间的超时操作。当异常已经修复的时候,应用会再次尝试执行操作。
熔断模式类似于容易失败操作的一种代理,它能够记录和统计最近执行失败的次数,然后决定是否继续执行,或者是立即返回错误。
实现熔断模式需要考虑以下三个状态:
- 闭合状态:熔断器会定义一个执行操作失败的计数器,在执行操作连续失败或者高频失败时,计数器数值会自增。如果计数器值大于某个阈值,则熔断器会切换到断开状态,同时熔断器会设置一个计时器,在经过一段时间之后会切换到半开状态;
- 断开状态:在断开状态下,应用执行操作会立即返回失败,或者可以在当本地缓存中没有数据时返回失败;
- 半开状态:在半开状态下,应用会被允许执行一次或者一些操作。如果这些操作执行成功,熔断器则会切换到闭合状态,同时会重置计数器。如果这些操作继续执行失败,熔断器则会重新切换到断开状态,同时会重置计时器。
限流
限流的目的是通过对并发访问进行限速。一般来说,限流的行为如下:
- 把多出来的请求拒绝掉;
- 关闭或者降级后端服务;
- 把有限资源分配给重要用户;
- 使用队列来削去请求高峰;
- 通过自动化运维的方式,实现服务的自动化伸缩。
限流的经典实现方式有基于计数器、漏斗算法、令牌桶算法。
计数器
使用计数器来实现限流的算法如下:
- 准备执行一个请求时,计数器加一;
- 执行完毕一个请求时,计数器减一;
- 当计数器值大于某个阈值时,开始限流。
在基于计数器的限流算法中,请求是以「次数」而不是以「频率」来被限制。
漏斗算法
漏斗算法的具体步骤如下:
- 用一个队列(在漏斗中接水)来堆积请求;
- Processor(从漏斗中出水)从队列中消费请求;
- 如果队列满了,则开始限流。
+-----------+ accept +-----------+
-------->| | | | | | |-------->| Processor |
+-----------+ +-----------+
|
| rejected
v
Discard
在漏斗算法中,请求是以 Processor 最大消费能力的频率来执行的。
令牌桶算法
令牌桶算法的具体步骤如下:
- 以恒定的速率产生 token,放入至一个集合(承担令牌桶角色)中;
- 准备执行一个请求时,从集合中获取一个 token;
- 当集合中没有 token 时,则开始限流。
+-----------+ add token
| | | | | | |<-----------
+-----------+
^
get token |
| accept
| +-----------+
----------+------->| Processor |
| +-----------+
| rejected
v
Discard
在令牌桶算法中,当令牌桶中有堆积的 token 时,请求可以被允许高频率地执行。
降级
降级的本质是为了解决在资源不足时,系统访问量过大的问题。当资源和访问量出现矛盾时,在资源有限的情况下,为了能够扛住大量的请求,而对系统进行降级操作。
一般来说,系统降级的策略有:
- 降低系统对一致性的要求;
- 完全停止次要功能,或者限制次要功能流量;
- 简化功能,例如只返回页面或者接口的部分信息。
一般来说,控制降级的形式是:
- 主动推送:开启系统配置;
- 由上游系统驱动:对外 API 的参数。