彈力設計之熔斷設計

熔斷機制這個詞肯定不陌生,它的靈感來源於我們電閘上的“保險絲”,當電壓有問題時(比如短路),自動跳閘,此時電路就會斷開,我們的電器就會受到保護。不然,會導致電器被燒壞,如果人沒在家或是人在熟睡中,還會導致火災。所以,在電路世界通常都會有這樣的自我保護裝置。

同樣,在我們的分佈式系統設計中,也應該有這樣的方式。前面說過重試機制,如果錯誤太多,或是在短時間內得不到修復,那麼我們重試也沒有意義了,此時應該開啓我們的熔斷操作,尤其是後端太忙的時候,使用熔斷設計可以保護後端不會過載。

熔斷設計

熔斷器模式可以防止應用程序不斷地嘗試執行可能會失敗的操作,使得應用程序繼續執行而不用等待修正錯誤,或者浪費 CPU 時間去等待長時間的超時產生。熔斷器模式也可以使應用程序能夠診斷錯誤是否已經修正。如果已經修正,應用程序會再次嘗試調用操作。

換句話來說,熔斷器模式就像是那些容易導致錯誤的操作的一種代理。這種代理能夠記錄最近調用發生錯誤的次數,然後決定是繼續操作,還是立即返回錯誤。



熔斷器可以使用狀態機來實現,內部模擬以下幾種狀態。

  • 閉合(Closed)狀態:我們需要一個調用失敗的計數器,如果調用失敗,則使失敗次數加 1。如果最近失敗次數超過了在給定時間內允許失敗的閾值,則切換到斷開 (Open) 狀態。此時開啓了一個超時時鐘,當該時鐘超過了該時間,則切換到半斷開(Half-Open)狀態。該超時時間的設定是給了系統一次機會來修正導致調用失敗的錯誤,以回到正常工作的狀態。在 Closed 狀態下,錯誤計數器是基於時間的。在特定的時間間隔內會自動重置。這能夠防止由於某次的偶然錯誤導致熔斷器進入斷開狀態。也可以基於連續失敗的次數。
  • 斷開 (Open) 狀態:在該狀態下,對應用程序的請求會立即返回錯誤響應,而不調用後端的服務。這樣也許比較粗暴,有些時候,我們可以 cache 住上次成功請求,直接返回緩存(當然,這個緩存放在本地內存就好了),如果沒有緩存再返回錯誤(緩存的機制最好用在全站一樣的數據,而不是用在不同的用戶間不同的數據,因爲後者需要緩存的數據有可能會很多)。
  • 半開(Half-Open)狀態:允許應用程序一定數量的請求去調用服務。如果這些請求對服務的調用成功,那麼可以認爲之前導致調用失敗的錯誤已經修正,此時熔斷器切換到閉合狀態,同時將錯誤計數器重置。
    如果這一定數量的請求有調用失敗的情況,則認爲導致之前調用失敗的問題仍然存在,熔斷器切回到斷開狀態,然後重置計時器來給系統一定的時間來修正錯誤。半斷開狀態能夠有效防止正在恢復中的服務被突然而來的大量請求再次拖垮。



    實現熔斷器模式使得系統更加穩定和有彈性,在系統從錯誤中恢復的時候提供穩定性,並且減少了錯誤對系統性能的影響。它快速地拒絕那些有可能導致錯誤的服務調用,而不會去等待操作超時或者永遠不返回結果來提高系統的響應時間。

下圖是 Netflix 的開源項目Hystrix中的熔斷的實現邏輯。



從這個流程圖中,可以看到:
1、有請求來了,首先 allowRequest() 函數判斷是否在熔斷中,如果不是則放行,如果是的話,還要看有沒有到達一個熔斷時間片,如果熔斷時間片到了,也放行,否則直接返回出錯。
2、每次調用都有兩個函數 markSuccess(duration) 和 markFailure(duration) 來統計一下在一定的 duration 內有多少調用是成功還是失敗的。
3、判斷是否熔斷的條件 isOpen(),是計算一下 failure/(success+failure) 當前的錯誤率,如果高於一個閾值,那麼打開熔斷,否則關閉。
4、Hystrix 會在內存中維護一個數組,其中記錄着每一個週期的請求結果的統計。超過時長長度的元素會被刪除掉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章