用golang實現一個熔斷器
阿新 • • 發佈:2019-01-01
首先貼出倉庫地址:https://github.com/JeffreyDing11223/goBreaker
這個熔斷器實現簡單,使用方便,同時大家也可以fork後進行自己需要的改造,當然,也歡迎大家提pr,一起優化goBreaker
下面介紹下goBreaker:
goBreaker狀態機
狀態轉換邏輯
- 初始為closed狀態,一旦遇到請求失敗時,會觸發熔斷檢測(見下方的 ShouldTrip),熔斷檢測來決定是否將狀態從closed轉為open。
- 當熔斷器為open狀態時,會熔斷所有當前服務要發出去的請求,直到冷卻時間(見下方的CoolingTimeout)結束,會從open轉變為half-open狀態。
- 當熔斷器為half-open狀態時,以檢測時間(見下方的 DetectTimeout)為週期去傳送請求。請求成功則計數器加1,當計數器達到一定閾值時則轉為closed狀態;請求失敗則轉為open狀態。
熔斷器內部資料結構
type Breaker struct {
Container // contains all success, error and timeout
sync.RWMutex
state State
openTime time.Time // the time when the breaker become OPEN
lastRetryTime time. Time // last retry time when in HALFOPEN state
halfopenSuccess int // consecutive successes when HALFOPEN
options Options
now func() time.Time
}
Breaker是暴露在最外層的struct,由以下屬性組成:
- Container:是一個interface,被 window 實現,負責熔斷器請求失敗,成功的相關計算和統計
- RW鎖:在http-gateway中,針對每個cmd有一個熔斷器,每個 cmd 同時會有多個goroutine併發請求,需要RW鎖來保持熔斷器中計數器,狀態等等的同步
- state:熔斷器三種狀態,closed,open 和 half-open
- openTime:當熔斷器變為 open 狀態時,記錄下的時間
- lastRetryTime:在 half-open 狀態時,會有個檢測週期,即每隔這個週期之後,熔斷器會放請求出去,同時更新這個 lastRetryTime。
- halfopenSuccess:在 half-open狀態時,當請求成功時,halfopenSuccess 會+1,當 halfopenSuccess 等於一個閾值時(預設為2),則變為 closed 狀態
- options:Breaker 的配置項,包括桶持有數量持有時間,冷卻時間,檢測週期,熔斷檢測回撥和狀態變化回撥等等
// Options for Breaker
type Options struct {
// parameters for container
BucketTime time.Duration // the time each bucket holds
BucketNums int // the number of buckets the breaker have
// parameters for breaker
BreakerRate float64
BreakerMinQPS int // when instance > 1, if qps is over this value, the breaker trip will work
BreakerMinSamples int // for RateTrip callback
CoolingTimeout time.Duration // fixed when create
DetectTimeout time.Duration // fixed when create
HalfOpenSuccess int
ShouldTrip TripFunc // trip callback, default is RateTrip func
StateChangeHandler StateChangeHandler
now func() time.Time
}
options是Breaker的配置項,有以下屬性組成:
- BucketTime:桶的線上時間
- BucketNums:window下持有桶的數量
- BrekaerRate:熔斷檢測回撥RateTrip的閾值
- BreakerMinQPS:當例項數量大於1時,並且開啟了動態策略時,用於計算BreakerMinSamples
- BreakerMinSamples:最小取樣數,配合RateTrip熔斷檢測回撥使用
- CoolingTimeout:保持 open 狀態直到冷卻時間結束,會從 open 轉變為 half-open 狀態,預設為5秒
- DetectTimeout:half-open 狀態時,每隔這個週期之後,熔斷器會放請求出去
- HalfOpenSuccess:half-open狀態變為closed狀態的判斷指標
- ShouldTrip:熔斷檢測回撥,為nil則代表不啟用熔斷功能
- StateChangeHandler:狀態變化回撥
type window struct {
sync.Mutex
oldest int // oldest bucket index
latest int // latest bucket index
buckets []*bucket // buckets this window has
bucketTime time.Duration // time each bucket holds
bucketNums int // the largest number of buckets of window could have
expireTime time.Duration // expire time of this window, equals to window size
inWindow int // the number of buckets in the window currently
conseErr int64 //consecutive errors
}
window負責熔斷器請求失敗,成功的相關計算和統計,有以下屬性組成:
- 互斥鎖:保證內部資料同步
- oldest:最老的桶,由 latest 桶變化而來,用於視窗下所有請求結果的儲存
- latest:最新的桶,每次統計請求結果時,用最新的桶來儲存
- buckets:所有桶
- bucketTime:latest 桶的線上時間,一旦 latest 桶下線,則變為 oldest 桶
- bucketNums:視窗最大持有桶的數量
- expireTime:oldest 桶的過期時間,一旦 oldest 桶過期,則從 window 中“移去”,expireTime = bucketTime*bucketNums
- inWindow:視窗當下持有桶的數量
- conseErr:連續錯誤數量,每次請求結果為成功時便清零
熔斷檢測回撥:
- ThresholdTripFunc:當失敗和超時的總數超過閾值,則熔斷
- ConsecutiveTripFunc:當連續錯誤總數(conseErr)超過閾值,則熔斷
- RateTripFunc:當視窗內請求總數大於最小取樣數且錯誤率(失敗+超時數量/請求總數)大於一定值時,則熔斷
api
- InitCircuitBreakers方法作為初始化熔斷器使用,這裡用cmd來區分各個breaker
- BreakerWhitelist 可以配置熔斷白名單,在白名單中的cmd不參與熔斷
- IsTriggerBreaker 判斷當前cmd的熔斷器的狀態,並告訴上層
- api比較簡單,可以直接閱讀原始碼來決定如何使用,倉庫地址見文首