最近看了一下go-kit,發現這個微服務框架的容斷器,也是使用sony開源的作爲基礎。
sony開源在 github 的容斷器
源代頭註釋中,原來實現的是微軟2015時公佈的標準,果然微軟纔開源界的大神。
Author: toontong
Date: 2018-07-26
1)微軟定義的 Circuit breaker
我不知道正確怎麼翻譯,直觀翻譯,可能叫:環形容斷器(或叫 循環狀態自動切換容斷器)。
因爲它是在下面3個狀態循環切換 :
Closed
/ \
Half-Open <--> Open
初始狀態是:Closed,指容斷器放行所有請求。
達到一定數量的錯誤計數,進入Open 狀態,指容斷髮生,下游出現錯誤,不能再放行請求。
經過一段Interval時間後,自動進入Half-Open狀態,然後開始嘗試對成功請求計數。
進入Half-Open後,根據成功/失敗計數(一段時間)情況,會自動進入Closed或Open。
2)sony開源的go實現
// 從定義的錯誤來看,sony的應該增加了對連接數進行了限制 。
var (
// ErrTooManyRequests is returned when the CB state is half open and the requests count is over the cb maxRequests
ErrTooManyRequests = errors.New("too many requests")
// ErrOpenState is returned when the CB state is open
ErrOpenState = errors.New("circuit breaker is open")
)
2.1) 通過Settings的實現,瞭解可配置功能:
type Settings struct {
Name string
MaxRequests uint32 // 半開狀態期最大允許放行請求:即進入Half-Open狀態時,一個時間週期內允許最大同時請求數(如果還達不到切回closed狀態條件,則不能再放行請求)。
Interval time.Duration // closed狀態時,重置計數的時間週期;如果配爲0,切入Open後永不切回Closed--有點暴力。
Timeout time.Duration // 進入Open狀態後,多長時間會自動切成 Half-open,默認60s,不能配爲0。
// ReadyToTrip回調函數:進入Open狀態的條件,比如默認是連接5次出錯,即進入Open狀態,即可對容斷條件進行配置。在fail+1 計數發生後,回調一次。
ReadyToTrip func(counts Counts) bool
// 狀態切換時的容斷器
OnStateChange func(name string, from State, to State)
}
2.2)核心的執行函數實現
func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) {
generation, err := cb.beforeRequest() //
if err != nil {
return nil, err
}
defer func() {
e := recover()
if e != nil {
cb.afterRequest(generation, false)
panic(e) // 如果代碼發生了panic,繼續panic給上層調用者去recover。
}
}()
result, err := req()
cb.afterRequest(generation, err == nil)
return result, err
}
2.2 關鍵 func beforeRequest()
函數做了幾件事:
0. 函數的核心功能:判斷是否放行請求,計數或達到切換新條件剛切換。
1. 判斷是否Closed,如是,放行所有請求。
-. 並且判斷時間是否達到Interval週期,從而清空計數,進入新週期,調用toNewGeneration()
2. 如果是Open狀態,返回ErrOpenState,—不放行所有請求。
-. 同樣判斷週期時間,到達則 同樣調用 toNewGeneration(){清空計數}
3. 如果是half-open狀態,則判斷是否已放行MaxRequests個請求,如未達到剛放行;否則返回:ErrTooManyRequests。
4. 此函數一旦放行請求,就會對請求計數加1(conut.onRequest()),請求後到另一個關鍵函數 : afterRequest()。
2.3 關鍵 func afterRequest()
- 函數核心內容很簡單,就對成功/失敗進行計數,達到條件則切換狀態。
- 與beforeRequest一樣,會調用公共函數 currentState(now)
-. currentState(now) 先判斷是否進入一個先的計數時間週期(Interval), 是則重置計數,改變容斷器狀態,並返回新一代。
-. 如果request耗時大於Interval, 幾本每次都會進入新的計數週期,容斷器就沒什麼意義了。
代碼的核心內容
- 使用了一個generation的概念,每一個時間週期(Interval)的計數(count)狀態稱爲一個generation。
- 在before/after的兩個函數中,實現了兩個狀態自動切換的機制:
-. 在同一個generation(即時間)週期內,計數滿足狀態切換條件,即自動切換;
-. 超過一個generation時間週期的也會自動切換;