成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Golang 熔斷器的實現

開發 后端
Go 項目中使用熔斷技術提高系統容錯性。本文介紹了 go 熔斷器和其使用。

 Go 項目中使用熔斷技術提高系統容錯性。本文介紹了 Go 熔斷器和其使用。

[[436616]]

熔斷器像是一個保險絲。當我們依賴的服務出現問題時,可以及時容錯。一方面可以減少依賴服務對自身訪問的依賴,防止出現雪崩效應;另一方面降低請求頻率以方便上游盡快恢復服務。

熔斷器的應用也非常廣泛。除了在我們應用中,為了請求服務時使用熔斷器外,在 web 網關、微服務中,也有非常廣泛的應用。本文將從源碼角度學習 sony 開源的一個熔斷器實現 github/sony/gobreaker。(代碼注釋可以從github/lpflpf/gobreaker 查看)

熔斷器的模式

gobreaker 是基于《微軟云設計模式》一書中的熔斷器模式的 Golang 實現。有 sony 公司開源,目前 star 數有 1.2K。使用人數較多。

下面是模式定義的一個狀態機:

熔斷器有三種狀態,四種狀態轉移的情況:

三種狀態:

  •  熔斷器關閉狀態,服務正常訪問
  •  熔斷器開啟狀態,服務異常
  •  熔斷器半開狀態,部分請求限流訪問

四種狀態轉移:

  •  在熔斷器關閉狀態下,當失敗后并滿足一定條件后,將直接轉移為熔斷器開啟狀態。
  •  在熔斷器開啟狀態下,如果過了規定的時間,將進入半開啟狀態,驗證目前服務是否可用。
  •  在熔斷器半開啟狀態下,如果出現失敗,則再次進入關閉狀態。
  •  在熔斷器半開啟后,所有請求(有限額)都是成功的,則熔斷器關閉。所有請求將正常訪問。

gobreaker 的實現

gobreaker 是在上述狀態機的基礎上,實現的一個熔斷器。

熔斷器的定義 

  1. type CircuitBreaker struct {   
  2.   name          string    
  3.   maxRequests   uint32  // 最大請求數 (半開啟狀態會限流)    
  4.   interval      time.Duration   // 統計周期    
  5.   timeout       time.Duration   // 進入熔斷后的超時時間    
  6.   readyToTrip   func(counts Counts) bool // 通過 Counts 判斷是否開啟熔斷。需要自定義    
  7.   onStateChange func(name string, from State, to State) // 狀態修改時的鉤子函數   
  8.   mutex      sync.Mutex // 互斥鎖,下面數據的更新都需要加鎖    
  9.   state      State  // 記錄了當前的狀態    
  10.   generation uint64 // 標記屬于哪個周期    
  11.   counts     Counts // 計數器,統計了 成功、失敗、連續成功、連續失敗等,用于決策是否進入熔斷    
  12.   expiry     time.Time // 進入下個周期的時間    
  13. }   

其中,如下參數是我們可以自定義的:

  •  MaxRequests:最大請求數。當在最大請求數下,均請求正常的情況下,會關閉熔斷器
  •  interval:一個正常的統計周期。如果為 0,那每次都會將計數清零
  •  timeout: 進入熔斷后,可以再次請求的時間
  •  readyToTrip:判斷熔斷生效的鉤子函數
  •  onStateChagne:狀態變更的鉤子函數

請求的執行

熔斷器的執行操作,主要包括三個階段;①請求之前的判定;②服務的請求執行;③請求后的狀態和計數的更新 

  1. // 熔斷器的調用    
  2. func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) {    
  3.    // ①請求之前的判斷    
  4.   generation, err :cb.beforeRequest()   
  5.   if err != nil {    
  6.     return nil, err    
  7.   }    
  8.   defer func() {   
  9.     e :recover()   
  10.     if e != nil {    
  11.       // ③ panic 的捕獲    
  12.       cb.afterRequest(generation, false)  
  13.       panic(e)    
  14.     }    
  15.   }()    
  16.   // ② 請求和執行    
  17.   result, err :req() 
  18.    // ③ 更新計數   
  19.   cb.afterRequest(generation, err == nil)    
  20.   return result, err    
  21. }   

請求之前的判定操作

請求之前,會判斷當前熔斷器的狀態。如果熔斷器以開啟,則不會繼續請求。如果熔斷器半開,并且已達到最大請求閾值,也不會繼續請求。 

  1. func (cb *CircuitBreaker) beforeRequest() (uint64, error) {    
  2.   cb.mutex.Lock()    
  3.   defer cb.mutex.Unlock()    
  4.   now :time.Now()    
  5.   state, generation :cb.currentState(now)    
  6.     if state == StateOpen { // 熔斷器開啟,直接返回    
  7.     return generation, ErrOpenState    
  8.   } else if state == StateHalfOpen && cb.counts.Requests >= cb.maxRequests { // 如果是半打開的狀態,并且請求次數過多了,則直接返回    
  9.     return generation, ErrTooManyRequests    
  10.   }    
  11.   cb.counts.onRequest()    
  12.   return generation, nil   
  13. }   

其中當前狀態的計算,是依據當前狀態來的。如果當前狀態為已開啟,則判斷是否已經超時,超時就可以變更狀態到半開;如果當前狀態為關閉狀態,則通過周期判斷是否進入下一個周期。 

  1. func (cb *CircuitBreaker) currentState(now time.Time) (State, uint64) {    
  2.   switch cb.state {    
  3.   case StateClosed:    
  4.     if !cb.expiry.IsZero() && cb.expiry.Before(now) { // 是否需要進入下一個計數周期    
  5.       cb.toNewGeneration(now)    
  6.     }    
  7.   case StateOpen:    
  8.     if cb.expiry.Before(now) {    
  9.       // 熔斷器由開啟變更為半開    
  10.       cb.setState(StateHalfOpen, now)   
  11.     }    
  12.   }    
  13.   return cb.state, cb.generation    
  14. }   

周期長度的設定,也是以據當前狀態來的。如果當前正常(熔斷器關閉),則設置為一個 interval 的周期;如果當前熔斷器是開啟狀態,則設置為超時時間(超時后,才能變更為半開狀態)。

請求之后的處理操作

每次請求之后,會通過請求結果是否成功,對熔斷器做計數。 

  1. func (cb *CircuitBreaker) afterRequest(before uint64, success bool) {    
  2.   cb.mutex.Lock()    
  3.   defer cb.mutex.Unlock()     
  4.   now :time.Now()      
  5.   // 如果不在一個周期,就不再計數    
  6.   state, generation :cb.currentState(now)   
  7.   if generation != before {   
  8.     return    
  9.   }    
  10.   if success {    
  11.     cb.onSuccess(state, now)    
  12.   } else {    
  13.     cb.onFailure(state, now)    
  14.   }    
  15. }   

如果在半開的狀態下:

  •  如果請求成功,則會判斷當前連續成功的請求數 大于等于 maxRequests, 則可以把狀態由半開狀態轉移為關閉狀態
  •  如果在半開狀態下,請求失敗,則會直接將半開狀態轉移為開啟狀態

如果在關閉狀態下:

  •  如果請求成功,則計數更新
  •  如果請求失敗,則調用 readyToTrip 判斷是否需要將狀態關閉狀態轉移為開啟狀態

總結

  •  對于頻繁請求一些遠程或者第三方的不可靠的服務,存在失敗的概率還是非常大的。使用熔斷器的好處就是可以是我們自身的服務不被這些不可靠的服務拖垮,造成雪崩。
  •  由于熔斷器里面,不僅會維護不少的統計數據,還有互斥鎖做資源隔離,成本也會不少。
  •  在半開狀態下,可能出現請求過多的情況。這是由于半開狀態下,連續請求成功的數量未達到最大請求值。所以,熔斷器對于請求時間過長(但是比較頻繁)的服務可能會造成大量的 too many requests 錯誤 
責任編輯:龐桂玉 來源: 馬哥Linux運維
相關推薦

2022-05-13 09:05:49

Hystrix熔斷器

2021-07-28 13:03:42

Golang熔斷語言

2023-08-28 08:00:45

2014-08-14 10:10:34

設計模式熔斷器

2022-07-05 09:44:25

服務治理熔斷限流

2025-04-03 10:04:53

服務降級分布式系統系統

2022-05-17 12:23:25

排序算法面試

2022-08-26 10:24:48

架構Golang

2023-01-26 00:59:39

B-Treegolang度量衡

2024-10-25 08:11:37

2023-09-27 18:02:31

2022-08-08 08:31:00

Linux內存管理

2022-12-28 08:08:57

2018-04-17 10:31:09

微服務架構Web

2022-12-31 14:51:48

微服務Golang

2021-07-20 10:30:46

Golanghttp語言

2023-11-09 07:23:57

Istio路由分析

2020-09-26 10:56:33

服務器熔斷服務隔離

2019-11-15 15:20:27

Golang編譯器前端

2024-10-09 17:19:04

GoGolangKubernetes
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 淫片一级国产 | 日韩在线精品强乱中文字幕 | 国产视频一区二区在线观看 | 日韩欧美亚洲一区 | 围产精品久久久久久久 | 中文字幕 亚洲一区 | 99综合| 日韩高清中文字幕 | 成人av免费网站 | 激情亚洲 | 亚洲精品一区二区冲田杏梨 | 国产综合久久 | 精品国产99 | 91小视频在线 | 老牛影视av一区二区在线观看 | av影音资源 | 亚洲成人免费视频在线观看 | 中文字幕一区二区三区四区 | 一区二区精品 | 中文字幕在线看 | 日本天天操 | 欧美亚洲视频在线观看 | 精品欧美乱码久久久久久 | 亚洲免费在线视频 | 午夜精品久久久久久久久久久久久 | 日韩视频一区在线观看 | 91成人免费| 久久天天躁狠狠躁夜夜躁2014 | 亚洲欧美日韩激情 | 成人乱人乱一区二区三区软件 | 日韩成人在线播放 | 国产精品91视频 | 中文字幕在线观看一区 | 欧美中文字幕在线观看 | 国产精品一区二区三区四区五区 | 高清久久久 | 精品国产免费一区二区三区演员表 | 亚洲欧洲激情 | 欧美视频免费 | 在线观看第一区 | 精品麻豆剧传媒av国产九九九 |