在微服務架構裏面一個很常見的問題就是服務之間的延遲和通訊失敗問題,極端的狀況下,甚至會由於某個服務的性能降低或者故障宕機,致使訪問超時,層層傳遞,引起雪崩,最終致使整個系統崩潰,而限流器和熔斷器(這兩個組件都是客戶端的)能很好的解決這個問題,提升系統的可靠性和穩定性git
限流器,從字面上理解就是用來限制流量,有時候流量突增(可預期的好比「雙11」,不可預期的微博的熱門話題等),會將後端服務壓垮,甚至直接宕機,使用限流器能限制訪問後端的流量,起到一個保護做用,被限制的流量,能夠根據具體的業務邏輯去處理,直接返回錯誤或者返回默認值等等github
golang 提供了拓展庫(golang.org/x/time/rate)提供了限流器組件,用法上也很簡單直觀,經過下面這段代碼就能夠建立一個限流器。golang
// 每 800ms 產生 1 個 token,最多緩存 1 個 token,若是緩存滿了,新的 token 會被丟棄 limiter := rate.NewLimiter(rate.Every(time.Duration(800)*time.Millisecond), 1)
限流器提供三種使用方式,Allow
,Wait
, Reserve
後端
Allow
: 返回是否有 token,沒有 token 返回 false,或者消耗 1 個 token 返回 trueWait
: 阻塞等待,知道取到 1 個 tokenReserve
: 返回 token 信息,Allow 其實至關於 Reserve().OK,此外還會返回須要等待多久纔有新的 token緩存
通常使用 Wait 的場景會比較多一些架構
if err := limiter.Wait(context.Background()); err != nil { panic(err) } // do you business logic
和限流器對依賴服務的保護機制不同,熔斷器是當依賴的服務已經出現故障時,爲了保證自身服務的正常運行再也不訪問依賴的服務,防止雪崩效應併發
熔斷器有三種狀態:運維
關閉狀態
:服務正常,並維護一個失敗率統計,當失敗率達到閥值時,轉到開啓狀態開啓狀態
:服務異常,調用 fallback 函數,一段時間以後,進入半開啓狀態半開啓裝態
:嘗試恢復服務,失敗率高於閥值,進入開啓狀態,低於閥值,進入關閉狀態github.com/afex/hystrix-go
,提供了 go 熔斷器實現,使用上面也很方便,首先建立一個熔斷器ide
hystrix.ConfigureCommand( "addservice", // 熔斷器名字,能夠用服務名稱命名,一個名字對應一個熔斷器,對應一份熔斷策略 hystrix.CommandConfig{ Timeout: 100, // 超時時間 100ms MaxConcurrentRequests: 2, // 最大併發數,超過併發返回錯誤 RequestVolumeThreshold: 4, // 請求數量的閥值,用這些數量的請求來計算閥值 ErrorPercentThreshold: 25, // 錯誤率閥值,達到閥值,啓動熔斷,25% SleepWindow: 1000, // 熔斷嘗試恢復時間,1000ms }, )
提供了阻塞和非阻塞兩種使用方式,完整代碼能夠參考以下連接: https://github.com/hatlonely/hellogolang/blob/master/sample/addservice/cmd/client/main.go函數
阻塞使用 Do
方法,返回一個 err
errc1 := hystrix.Go("addservice", func() error { var err error ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50*time.Millisecond)) defer cancel() res1, err = client.Add(ctx, req) if err == nil { success <- struct{}{} } return err }, nil) // 有 fallback 處理 errc2 := hystrix.Go("addservice", func() error { var err error ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50*time.Millisecond)) defer cancel() res2, err = client.Add(ctx, req) if err == nil { success <- struct{}{} } return err }, func(err error) error { fmt.Println(err) res2 = &addservice.AddResponse{V: req.A + req.B} success <- struct{}{} return nil }) for i := 0; i < 2; i++ { select { case <-success: fmt.Println("success", i) case err := <-errc1: fmt.Println("err1:", err) case err := <-errc2: // 這個分支永遠不會走到,由於熔斷機制裏面永遠不會返回錯誤 fmt.Println("err2:", err) } }
測試代碼: https://github.com/hatlonely/hellogolang/blob/master/sample/addservice/cmd/client/main.go
Circuit Breaker Pattern: https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589784(v%3dpandp.10)
hystrix-go: https://github.com/afex/hystrix-go/
轉載請註明出處
本文連接:http://www.hatlonely.com/2018/06/21/微服務組件之限流器與熔斷器/
第 19 期Python實戰班正在火熱招生中
第 8 期自動化運維班正在招生中
第4期golang正在招生中
詳情掃碼諮詢
免費視頻 戳戳戳!