熔断器的实现参考了Google SRE过载保护算法,该算法的原理如下:
- 请求数量(requests):调用方发起请求的数量总和
- 请求接受数量(accepts):被调用方正常处理的请求数量
在正常情况下,这两个值是相等的,随着被调用方服务出现异常开始拒绝请求,请求接受数量(accepts)的值开始逐渐小于请求数量(requests),这个时候调用方可以继续发送请求,直到requests = K * accepts,一旦超过这个限制,熔断器就回打开,新的请求会在本地以一定的概率被抛弃直接返回错误,概率的计算公式如下:
image.png
大白话解释:
也就是说,当 accepts 的数量少于 requests 的时候;也就是出现请求错误,那这个公式就会出现正数,也就是会有一个分数出来,这个就是本地直接抛弃该请求(不向后端发送)的概率。
如何使用:
拿 kratos 中的代码来做例子;
// NewBreaker return a sreBresker with options
func NewBreaker(opts ...Option) circuitbreaker.CircuitBreaker {
opt := options{
success: 0.6,
request: 100,
bucket: 10,
window: 3 * time.Second,
}
for _, o := range opts {
o(&opt)
}
counterOpts := window.RollingCounterOpts{
Size: opt.bucket,
BucketDuration: time.Duration(int64(opt.window) / int64(opt.bucket)),
}
stat := window.NewRollingCounter(counterOpts)
return &Breaker{
stat: stat,
//这个 r 就是用来比对是否可发起请求的阀值
r: rand.New(rand.NewSource(time.Now().UnixNano())),
request: opt.request,
k: 1 / opt.success,
state: StateClosed,
}
}
。。。
。。。
。。。
// Allow request if error returns nil.
func (b *Breaker) Allow() error {
// The number of requests accepted by the backend
accepts, total := b.summary()
// The number of requests attempted by the application layer(at the client, on top of the adaptive throttling system)
requests := b.k * float64(accepts)
// check overflow requests = K * accepts
if total < b.request || float64(total) < requests {
if atomic.LoadInt32(&b.state) == StateOpen {
atomic.CompareAndSwapInt32(&b.state, StateOpen, StateClosed)
}
return nil
}
if atomic.LoadInt32(&b.state) == StateClosed {
atomic.CompareAndSwapInt32(&b.state, StateClosed, StateOpen)
}
dr := math.Max(0, (float64(total)-requests)/float64(total+1))
drop := b.trueOnProba(dr)
if drop {
return circuitbreaker.ErrNotAllowed
}
return nil
}
。。。
。。。
。。。
func (b *Breaker) trueOnProba(proba float64) (truth bool) {
b.randLock.Lock()
truth = b.r.Float64() < proba
b.randLock.Unlock()
return
}
1.定义
NewBreaker 中,随机定义了阀值 r
,用于比对通过概率。
code github address : https://github.com/go-kratos/aegis
2.允许逻辑(公式实现)
Allow 中 首先获取请求数和数,并且计算公式结果
3.通过概率比较
trueOnProba 方法是直接的比较大小,这里就体现了这个随机丢弃的逻辑。