• 微服务中的服务熔断有什么用?
  • 发布于 2个月前
  • 85 热度
    0 评论

微服务领域里有个词叫服务熔断,你知道这是啥不?故事要从我读大学那会说起。因为功率问题,很多寝室都是不让用吹风筒和热水壶的。但我那时候头铁,不仅用,而且还同时开了两个热水壶和一个吹风筒。直接给寝室电路来了个压测。不出意外的出了意外,寝室直接停电。一时间,隔壁寝室灯火通明,我们寝室一片漆黑。作为本科专业电气工程的靓仔,我们意识到,这妥妥是电路过载导致断路器跳闸了。于是我们趁社管阿姨不注意,偷偷摸进配电房,手动将断路器开关复位,寝室就来电了。是真的有惊无险。


如果没有这个断路器,寝室总电路怕是得因为过载全部烧掉,我们几个妥妥会提前进入社会大学。我能毕业,全靠这个断路器!看到这里,我们知道了断路器的作用,就是在电路出问题的时候及时断开电路,避免过载,从而保护电路。在微服务领域,我们也可以借鉴断路器的思路,引入了服务熔断的概念。

服务熔断是什么
服务熔断,也就是 Circuit Breaker,本质上是一种软件设计模式,用于在分布式系统中处理服务调用失败的情况。假设有个 A 服务调用 B 服务的场景,如果 B 服务已经出现频繁失败的情况,A 继续调用只会加剧 B 服务的负担,严重的时候,有可能导致 B 服务崩溃,甚至出现 B 服务重启后立马被打崩的情况。因此,最好的做法是,在一段时间内先不要再频繁调用 B 服务。

为了实现这个保护效果,我们可以在 A 和 B 之间加一个熔断器。当 B 服务频繁失败时,熔断器可以防止 A 继续频繁调用 B 服务,相当于阻断服务间的请求,并且还能在 B 服务恢复正常之后,恢复 A 对 B 的调用。

工作原理也和上文提到的宿舍电路里的断路器类似。当服务调用失败的次数超过某个阈值时,熔断器会自动“打开”(Open),阻止进一步的服务调用,防止不断报错重试导致压垮被调用服务。然后在在一段时间之后,熔断器开始尝试允许少量的请求通过,以检查服务是否已经恢复,也就是所谓的“半打开”(HalfOpen)。

如果这些请求成功,熔断器会“关闭”(Close),系统恢复正常的服务调用;但如果调用还是失败,那熔断器会继续再次回到“打开”(Open)状态。上面提到的三个状态Open,HalfOpen和Close是服务熔断中非常重要的三个状态。

• Closed(关闭):这是熔断器的初始状态。在这种状态下,可以进行服务间调用,熔断器会跟踪服务调用的成功和失败情况。如果失败调用次数,到了某个配置的阈值,熔断器就会切换到 Open(打开)状态。

• HalfOpen(半开):保持 Open 状态一段时间后,熔断器会尝试进入 HalfOpen 状态。这个状态下,熔断器会尝试放几个请求通过,看下被调用服务是否已经恢复。如果这些请求成功,熔断器就会回到 Closed 状态;如果失败,那它会退回到 Open 状态。

• Open(打开):当熔断器检测到服务调用连续失败时,它会切换到 Open 状态。在这种状态下,熔断器会阻止所有对服务的调用,直到超时时间过后,或者在 HalfOpen 状态下的探测请求成功。

它们的状态流转关系就像下图这样。

怎么使用熔断器?
可以看出,熔断器的逻辑其实很简单,而且这么通用的功能,必然有现成的库可以直接拿来用。比如阿里开源的sentinel-golang。
使用也比较简单。只需要三步。
1.引入 circuitbreaker 库
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
2.声明熔断规则
通过circuitbreaker.LoadRules加载对应的熔断规则。
    _, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
        // Statistic time span=5s, recoveryTimeout=3s, maxErrorRatio=40%
        {
            Resource:                     "api_url",
            Strategy:                     circuitbreaker.ErrorRatio,
            RetryTimeoutMs:               3000,
            MinRequestAmount:             10,
            StatIntervalMs:               5000,
            StatSlidingWindowBucketCount: 10,
            Threshold:                    0.4,
        },
    })
这里面有几个需要注意的地方:
• Resource 是想要保护的资源名称,也就是上面提到的 B 服务,这里可以直接使用被调用方的 url。
• Strategy 是指熔断策略,示例代码里展示的是错误率,也就是说服务达到 xx 比例的错误率时就会触发熔断。同时这里还支持填其他策略,比如从错误率换成错误次数或者是慢调用的比例个数。
• RetryTimeoutMs 是指熔断器打开后经过多长时间后进行重试。在熔断器 Open 期间,请求会被直接拒绝,不会发送到后端 Resource(B 服务)。在指定的超时时间之后,熔断器将尝试发送一个请求以检查后端资源的可用性。

• MinRequestAmount 表示在进行熔断之前必须满足的最小请求数量。只有当请求的数量达到或超过这个阈值时,熔断器才会生效。这个参数可以用来避免在系统启动时就触发熔断。

• StatIntervalMs 表示统计信息的时间间隔,以毫秒为单位。在这个时间间隔内,熔断器将收集请求的统计信息,用于计算错误率。
• Threshold:表示错误率的阈值。当错误率超过这个阈值时,熔断器将触发熔断,停止发送请求到后端资源。

3.加入熔断保护
在需要进行熔断保护的地方,加入下面的代码:
        e, b := sentinel.Entry("api_url")
        if b == nil {
            // 通过检测,不需要熔断,直接执行api调用
            err := api_call()
            if err != nil {
                sentinel.TraceError(e, err)
            }
            // 堆代码 duidaima.com
            // 保证执行完之后退出资源
            e.Exit()
        }
上面的 sentinel.Entry()方法内部会自动检测"api_url"这个资源是否需要打开熔断器,如果 api 调用报错了,可以通过 sentinel.TraceError 记录下来,sentinel 内部会根据报错去计算报错率,自动判断要不要熔断。

到这里,就算使用上熔断器的能力啦。

总结
• 服务熔断是一种软件设计模式,用于分布式系统中处理服务调用失败的情况,可以防止被调用服务因为频繁失败被压垮。它借鉴了电路中的断路器原理,通过监控服务调用的失败率等条件来决定是否阻止进一步的调用,以保护系统免受过载。

• 服务熔断器有三个主要状态:关闭(Closed)、半开(HalfOpen)和打开(Open),分别对应不同的保护策略。当服务调用失败次数超过阈值时,熔断器打开,阻止服务调用。在一定时间后,熔断器尝试半开状态,允许少量请求通过以测试服务恢复情况。如果服务恢复,熔断器关闭;如果失败,熔断器保持打开状态。

• 在 go 语言里可以使用 sentinel-golang 库实现熔断功能。
用户评论