在高可用设计中,除了流控外,对分布式系统调用链路中不稳定的资源(比如 RPC 服务等)进行熔断降级也是保障高可用的重要措施之一。

现代微服务架构基本都是分布式的,整个分布式系统由非常多的微服务组成。不同服务之间相互调用,组成复杂的调用链路。因此我们需要对不稳定的 弱依赖服务调用 进行 熔断降级,暂时切断不稳定的服务调用,避免局部不稳定因素导致整个分布式系统的雪崩。

熔断降级作为保护服务自身的手段,通常在客户端(调用端)进行配置。

sentinel 熔断器

Sentinel 熔断降级基于熔断器模式 (circuit breaker pattern) 实现。熔断器内部维护了一个熔断器的状态机,状态机的转换关系如下图所示:

这三种状态的转换关系解释:

  • 初始状态下,熔断器处于 Closed 状态。如果基于熔断器的统计数据表明当前资源触发了设定的阈值,那么熔断器会切换状态到 Open 状态;
  • Open 状态即代表熔断状态,所有请求都会直接被拒绝。熔断器规则中会配置一个熔断超时重试的时间,经过熔断超时重试时长后熔断器会将状态置为 Half-Open 状态,从而进行探测机制;
  • 处于 Half-Open 状态的熔断器会周期性去做探测。

熔断策略

Sentinel 支持以下几种熔断策略:

1、慢调用比例策略 (SlowRequestRatio):

Sentinel 的熔断器不在静默期,并且慢调用的比例大于设置的阈值,则接下来的熔断周期内对资源的访问会自动地被熔断。该策略下需要设置允许的调用 RT 临界值(即最大的响应时间),对该资源访问的响应时间大于该阈值则统计为慢调用。

2、错误比例策略 (ErrorRatio):

Sentinel 的熔断器不在静默期,并且在统计周期内资源请求访问异常的比例大于设定的阈值,则接下来的熔断周期内对资源的访问会自动地被熔断。

3、错误计数策略 (ErrorCount):

Sentinel 的熔断器不在静默期,并且在统计周期内资源请求访问异常数大于设定的阈值,则接下来的熔断周期内对资源的访问会自动地被熔断。

注意:这里的错误比例熔断和错误计数熔断指的业务返回错误的比例或则计数。也就是说,如果规则指定熔断器策略采用错误比例或则错误计数,那么为了统计错误比例或错误计数,需要调用API: api.TraceError(entry, err) 埋点每个请求的业务异常。

规则定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
type Rule struct {
	// 全局唯一 ID,可选项。
	Id string `json:"id,omitempty"`
	// 熔断器生效的资源名
    Resource string   `json:"resource"`
    // 熔断策略,目前支持 SlowRequestRatio、ErrorRatio、ErrorCount 三种;
    // 选择以慢调用比例 (SlowRequestRatio) 作为阈值,需要设置允许的最大响应时间(MaxAllowedRtMs),请求的响应时间大于该值则统计为慢调用。通过 Threshold 字段设置触发熔断的慢调用比例,取值范围为 [0.0, 1.0]。规则配置后,在单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态,若接下来的一个请求响应时间小于设置的最大 RT 则结束熔断,若大于设置的最大 RT 则会再次被熔断。
    // 选择以错误比例 (ErrorRatio) 作为阈值,需要设置触发熔断的异常比例(Threshold),取值范围为 [0.0, 1.0]。规则配置后,在单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态,若接下来的一个请求没有错误则结束熔断,否则会再次被熔断。代码中可以通过 api.TraceError(entry, err) 函数来记录 error。
    // 选择以错误数(ErrorCount)作为阈值,需要设置触发熔断的异常比例(Threshold),表示错误计数的阈值。
	Strategy Strategy `json:"strategy"`
	// 熔断触发后持续的时间(单位为 ms)。资源进入熔断状态后,在配置的熔断时长内,请求都会快速失败。熔断结束后进入探测恢复模式(HALF-OPEN)。
	RetryTimeoutMs uint32 `json:"retryTimeoutMs"`
    // 静默数量,如果当前统计周期内对资源的访问数量小于静默数量,那么熔断器就处于静默期。
    // 换言之,也就是触发熔断的最小请求数目,若当前统计周期内的请求数小于此值,即使达到熔断条件规则也不会触发。
	MinRequestAmount uint64 `json:"minRequestAmount"`
	// 统计的时间窗口长度(单位为 ms)。
	StatIntervalMs uint32 `json:"statIntervalMs"`
	// StatSlidingWindowBucketCount 表示统计滑动窗口的桶数,默认为 1。
    // 随着桶数的增加,统计数据会更精确,但内存消耗也会增加。
    // 以下必须为真- " StatIntervalMs % StatSlidingWindowBucketCount == 0 ",
    // 否则 StatSlidingWindowBucketCount 将被替换为1。
    // 如果没有设置,则使用默认值1。
	StatSlidingWindowBucketCount uint32 `json:"statSlidingWindowBucketCount"`
    // 仅对慢调用熔断策略生效,MaxAllowedRtMs 是判断请求是否是慢调用的临界值,也就是:
    // - 如果请求的response time小于或等于MaxAllowedRtMs,那么就不是慢调用;
    // - 如果response time大于MaxAllowedRtMs,那么当前请求就属于慢调用。
	MaxAllowedRtMs uint64 `json:"maxAllowedRtMs"`
    // - 对于慢调用熔断策略, Threshold表示是慢调用比例的阈值(小数表示,比如0.1表示10%),也就是如果当前资源的慢调用比例如果高于Threshold,那么熔断器就会断开;否则保持闭合状态。
    // - 对于错误比例策略,Threshold表示的是错误比例的阈值(小数表示,比如0.1表示10%)。
    // - 对于错误数策略,Threshold是错误计数的阈值。
	Threshold float64 `json:"threshold"`
}

补充:

Resource、Strategy、RetryTimeoutMs、MinRequestAmount、StatIntervalMs、Threshold 每个规则都必设的字段,MaxAllowedRtMs 是慢调用比例熔断规则必设的字段。

场景示例

这里分别给出三种熔断策略规则配置的一个Sample(不可作为线上配置参考):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 慢调用比例规则
rule1 := &Rule{
    Resource:         "abc",
    Strategy:         SlowRequestRatio,
    RetryTimeoutMs:   5000,
    MinRequestAmount: 10,
    StatIntervalMs:   10000,
    MaxAllowedRtMs:   20,
    Threshold:        0.1,
},
// 错误比例规则
rule1 := &Rule{
    Resource:         "abc",
    Strategy:         ErrorRatio,
    RetryTimeoutMs:   5000,
    MinRequestAmount: 10,
    StatIntervalMs:   10000,
    Threshold:        0.1,
},
// 错误计数规则
rule1 := &Rule{
    Resource:         "abc",
    Strategy:         ErrorCount,
    RetryTimeoutMs:   5000,
    MinRequestAmount: 10,
    StatIntervalMs:   10000,
    Threshold:        100,
},

参考

sentinel 官方文档