go容斷器源碼:github.com/sony/gobreaker

最近看了一下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後,根據成功/失敗計數(一段時間)情況,會自動進入ClosedOpen

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()

  1. 函數核心內容很簡單,就對成功/失敗進行計數,達到條件則切換狀態。
  2. 與beforeRequest一樣,會調用公共函數 currentState(now)
    -. currentState(now) 先判斷是否進入一個先的計數時間週期(Interval), 是則重置計數,改變容斷器狀態,並返回新一代。
    -. 如果request耗時大於Interval, 幾本每次都會進入新的計數週期,容斷器就沒什麼意義了。

代碼的核心內容

  1. 使用了一個generation的概念,每一個時間週期(Interval)的計數(count)狀態稱爲一個generation。
  2. 在before/after的兩個函數中,實現了兩個狀態自動切換的機制:
    -. 在同一個generation(即時間)週期內,計數滿足狀態切換條件,即自動切換;
    -. 超過一個generation時間週期的也會自動切換;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章