在实际应用中,熔断降级通常在客户端(调用端)进行配置。例如,在服务A调用服务B的接口时,服务A的代码中会配置熔断器,通过监控服务B的响应情况,当检测到服务B的响应异常时,触发熔断机制,暂时停止对服务B的调用,而是直接返回一个预设的默认值或错误信息,从而保护服务A免受服务B不稳定性的影响。
熔断器内部维护了一个状态机:
熔断器有三种状态:
这三种状态之间的转换关系这里做一个更加清晰的解释:
熔断策略:Sentinel支持三种熔断策略,即慢调用比例熔断、异常比例熔断和异常数量熔断。根据这些策略,用户可以设置熔断规则来为资源添加熔断器。
熔断器:每个熔断规则都会被转换成对应的熔断器,熔断器对用户是不可见的。每个熔断器都有自己独立的统计结构。
熔断器的整体检查逻辑:
静默期:三种熔断策略都支持静默期,静默期指的是最小的静默请求数,在一个统计周期里,如果对资源的请求数小于设置的静默数,熔断器不会基于统计值去更改熔断器的状态。比如在统计周期刚开始的时候,第一个请求恰好是慢请求,这时候慢调用比例是100%,显然不合理。静默期提高了熔断器的精准性且降低了误判的可能性。支持的几种熔断策略:(前提都是不在静默期)
如果规则指定熔断器策略采用错误比例或则错误计数,那么为了统计错误比例或错误计数,需要调用API:api.TraceError(entry,err)埋点每个请求的业务异常。
Strategy:熔断策略,目前支持SlowRequestRatio、ErrorRatio、ErrorCount三种;
选择慢调用比例(SlowRequestRatio)作为阈值:
选择错误比例(ErrorRatio)作为阈值:
Threshold:
MaxAllowedRtMs:
其他字段:
配置参考
分布式系统中降级:假设存在应用A需要调用应用B的接口(特别是一些对接外部公司或者业务的接口时候),那么一般用于A调用B的接口时的防护;数据库慢调用的防护:假设应用需要读/写数据库,但是该读写SQL存在潜在慢SQL的可能性,那么可以对该读写接口做防护,当接口不稳定时候(存在慢SQL),那么基于熔断器做降级。也可以是应用中任意弱依赖接口做降级防护(即自动降级后不影响业务核心链路)
在热点参数流控中是根据MetricType+ControlBehavior组合来提供不同的流控策略,相比于流量控制的多种流控方式热点参数流控方式只有三种:
在常见的缓存淘汰算法中有LRU和LFU
热点数据的统计比较符合LRU算法的特点,所以在SentinelGo中选择使用LRU策略统计最近最常访问的热点参数,下面来看一下具体的工程实现:
首先在hotspot模块下有一个Cache目录,在Cache目录里有ConcurrentCounterCache接口,此接口是对热点参数统计结构的抽象,实现此接口就可以作为热点参数限流的统计结构
typeConcurrentCounterCacheinterface{Add(keyinterface{},value*int64)AddIfAbsent(keyinterface{},value*int64)(priorValue*int64)Get(keyinterface{})(value*int64,isFoundbool)Remove(keyinterface{})(isFoundbool)Contains(keyinterface{})(okbool)Keys()[]interface{}Len()intPurge()}在Cache目录下的concurrent_lru.go文件中是ConcurrentCounterCache接口的具体实现,concurrent_lru中实现了并发安全的lru算法
typeLruCacheMapstruct{//Notthreadsafelru*LRUlock*sync.RWMutex}func(c*LruCacheMap)Add(keyinterface{},value*int64){c.lock.Lock()deferc.lock.Unlock()c.lru.Add(key,value)return}func(c*LruCacheMap)Get(keyinterface{})(value*int64,isFoundbool){c.lock.Lock()deferc.lock.Unlock()val,found:=c.lru.Get(key)iffound{returnval.(*int64),true}returnnil,false}在Cache目录下的lru.go中则是lru算法的真正实现,也是热点数据真正存储的数据结构(在LRU算法中Add,Get等操作会将元素移动到队列头部,当元素中个数超过容量时会将队尾元素淘汰)
并发超过阈值直接拒绝的流程比较简单,只需要用到统计结构(ParamsMetric)中的ConcurrencyCounter来记录热点参数值的并发数量即可,如下: