如今,我們的應用程式依賴其他應用程式是很常見的,特別是當我們在微服務環境中工作時。我們的應用程式開始報告錯誤是很常見的,在調查時,我們注意到合作夥伴團隊或供應商的某些 API 已關閉。
提高應用程式彈性的一個好做法是切斷與那些處於棄用狀態的應用程式的通訊。觀察其他領域,我們吸收了電機工程中斷路器的概念。其中放置了一個設備或斷路器,如果發生故障,它會自動關閉。這在我們的家裡很常見,如果電網開始變得不穩定,斷路器會自行關閉。
在計算中,我們的斷路器稍微複雜一些,因為我們也定義了中間狀態。下圖更好地解釋了斷路器的工作原理:
最後,狀態是:
很酷,對吧?但為了更好地舉例說明這個概念,我們在實踐中該如何做呢?
首先,我們來建構我們的服務A。它將負責接收請求,也就是說,它將是我們的應用程式所依賴的服務,供應商的服務等。為了方便起見,我們將公開兩個端點,一個始終返回 200 的 /success 和一個始終返回 500 的 /failure。
package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/success", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) http.HandleFunc("/failure", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) }) fmt.Println("Server is running at http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
服務 B 將負責呼叫服務 A。它將建造我們的斷路器。對我們來說幸運的是,Go 社群已經有了實現該模式的 gobreaker 函式庫!首先,我們定義斷路器的屬性:
var st gobreaker.Settings st.Name = "Circuit Breaker PoC" st.Timeout = time.Second * 5 st.MaxRequests = 2 st.ReadyToTrip = func(counts gobreaker.Counts) bool { return counts.ConsecutiveFailures >= 1 }
雖然該庫允許我們定制更多的東西,但我們將重點放在三個:
然後我們可以初始化斷路器並發出請求:
cb := gobreaker.NewCircuitBreaker[int](st) url := "http://localhost:8080/success" cb.Execute(func() (int, error) { return Get(url) }) fmt.Println("Circuit Breaker state:", cb.State()) // closed! url = "http://localhost:8080/failure" cb.Execute(func() (int, error) { return Get(url) }) fmt.Println("Circuit Breaker state:", cb.State()) // open! time.Sleep(time.Second * 6) url = "http://localhost:8080/success" cb.Execute(func() (int, error) { return Get(url) }) fmt.Println("Circuit Breaker state:", cb.State()) // half-open! url = "http://localhost:8080/success" cb.Execute(func() (int, error) { return Get(url) }) fmt.Println("Circuit Breaker state:", cb.State()) // closed!
我們可以注意到 gobreaker 作為函數的包裝器。如果函數傳回錯誤,則會增加錯誤數量,如果沒有,則會增加成功數量。那麼讓我們定義這個函數:
func Get(url string) (int, error) { r, _ := http.Get(url) if r.StatusCode != http.StatusOK { return r.StatusCode, fmt.Errorf("failed to get %s", url) } return r.StatusCode, nil }
我們的 Go 服務使用了斷路器!透過使用此模式,您可以提高服務的彈性和容錯能力。我們可以注意到,在使用該庫時,複雜性被完全抽象,使得將其整合到我們日常生活中的過程非常簡單。如果您想查看完整的概念驗證程式碼,請前往此處。
如果您想了解其他彈性模式,Elton Minetto 發表了一篇關於該主題的精彩文章!
請在評論中告訴我您對這篇文章的看法,這裡有一個問題:您以前使用過斷路器嗎?哦,你也可以在我的個人部落格找到我!
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3