熔斷器的實現(xiàn)參考了Google SRE過載保護算法,該算法的原理如下:
- 請求數(shù)量(requests):調(diào)用方發(fā)起請求的數(shù)量總和
- 請求接受數(shù)量(accepts):被調(diào)用方正常處理的請求數(shù)量
在正常情況下,這兩個值是相等的,隨著被調(diào)用方服務(wù)出現(xiàn)異常開始拒絕請求,請求接受數(shù)量(accepts)的值開始逐漸小于請求數(shù)量(requests),這個時候調(diào)用方可以繼續(xù)發(fā)送請求,直到requests = K * accepts,一旦超過這個限制,熔斷器就回打開,新的請求會在本地以一定的概率被拋棄直接返回錯誤,概率的計算公式如下:

image.png
大白話解釋:
也就是說,當(dāng) accepts 的數(shù)量少于 requests 的時候;也就是出現(xiàn)請求錯誤,那這個公式就會出現(xiàn)正數(shù),也就是會有一個分數(shù)出來,這個就是本地直接拋棄該請求(不向后端發(fā)送)的概率。
如何使用:
拿 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 就是用來比對是否可發(fā)起請求的閥值
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.允許邏輯(公式實現(xiàn))
Allow 中 首先獲取請求數(shù)和數(shù),并且計算公式結(jié)果
3.通過概率比較
trueOnProba 方法是直接的比較大小,這里就體現(xiàn)了這個隨機丟棄的邏輯。