微服务的容错模式
http://www.360doc.com/content/18/0222/08/10346540_731371833.shtml
在使用了微服務架構以后,整體的業務流程被拆分成小的微服務,并組合在一起對外提供服務,微服務之間使用輕量級的網絡協議通信,通常是RESTful風格的遠程調用。由于服務與服務的調用不再是進程內的調用,而是通過網絡進行的遠程調用,眾所周知,網絡通信是不穩定、不可靠的,一個服務依賴的服務可能出錯、超時或者宕機,如果沒有及時發現和隔離問題,或者在設計中沒有考慮如何應對這樣的問題,那么很可能在短時間內服務的線程池中的線程被用滿、資源耗盡,導致出現雪崩效應。本節針對微服務架構中可能遇到的這些問題,講解應該采取哪些措施和方案來解決。
1. 艙壁隔離模式
這里用航船的設計比喻艙壁隔離模式,若一艘航船遇到了意外事故,其中一個船艙進了水,則我們希望這個船艙和其他船艙是隔離的,希望其他船艙可以不進水,不受影響。在微服務架構中,這主要體現在如下兩個方面。
1)微服務容器分組
筆者所在的支付平臺應用了微服務,將微服務的每個節點的服務池分為三組:準生產環境、灰度環境和生產環境。準生產環境供內側使用;灰度環境會跑一些普通商戶的流量;大部分生產流量和VIP商戶的流量則跑在生產環境中。這樣,在一次比較大的重構過程中,我們就可以充分利用灰度環境的隔離性進行預驗證,用普通商戶的流量驗證重構沒有問題后,再上生產環境。
另外一個案例是一些社交平臺將名人的自媒體流量全部路由到服務的核心池子中,而將普通用戶的流量路由到另外一個服務池子中,有效隔離了普通用戶和重要用戶的負載。
其服務分組如圖1-27所示。
?
?
圖1-27?
2)線程池隔離
在微服務架構實施的過程中,我們不一定將每個服務拆分到微小的力度,這取決于職能團隊和財務的狀況,我們一般會將同一類功能劃分在一個微服務中,盡量避免微服務過細而導致成本增加,適可而止。
這樣就會導致多個功能混合部署在一個微服務實例中,這些微服務的不同功能通常使用同一個線程池,導致一個功能流量增加時耗盡線程池的線程,而阻塞其他功能的服務。
線程池隔離如圖1-28所示。
?
圖1-28
2. 熔斷模式
可以用家里的電路保險開關來比喻熔斷模式,如果家里的用電量過大,則電路保險開關就會自動跳閘,這時需要人工找到用電量過大的電器來解決問題,然后打開電路保險開關。在這個過程中,電路保險開關起到保護整個家庭電路系統的作用。
對于微服務系統也一樣,當服務的輸入負載迅速增加時,如果沒有有效的措施對負載進行熔斷,則會使服務迅速被壓垮,服務被壓垮會導致依賴的服務都被壓垮,出現雪崩效應,因此,可通過模擬家庭的電路保險開關,在微服務架構中實現熔斷模式。
微服務化的熔斷模式的狀態流轉如圖1-29所示。
?
?
圖1-29?
3. 限流模式
服務的容量和性能是有限的,在第3章中會介紹如何在架構設計過程中評估服務的最大性能和容量,然而,即使我們在設計階段考慮到了性能壓力的問題,并從設計和部署上解決了這些問題,但是業務量是隨著時間的推移而增長的,突然上量對于一個飛速發展的平臺來說是很常見的事情。
針對服務突然上量,我們必須有限流機制,限流機制一般會控制訪問的并發量,例如每秒允許處理的并發用戶數及查詢量、請求量等。
有如下幾種主流的方法實現限流。
1)計數器
通過原子變量計算單位時間內的訪問次數,如果超出某個閾值,則拒絕后續的請求,等到下一個單位時間再重新計數。
在計數器的實現方法中通常定義了一個循環數組(見圖1-30),例如:定義5個元素的環形數組,計數周期為1s,可以記錄4s內的訪問量,其中有1個元素為當前時間點的標志,通常來說每秒程序都會將前面3s的訪問量打印到日志,供統計分析。
?
圖1-30?
我們將時間的秒數除以數組元素的個數5,然后取模,映射到環形數組里的數據元素,假如當前時間是1 000 000 002s,那么對應當前時間的環形數組里的第3個元素,下標為2。
此時的數組元素的數據如圖1-31所示。
?
圖1-31?
在圖1-31中,當前時間為1 000 000 002s,對應的計數器在第3個元素,下標為2,當前請求是在這個時間周期內的第1個訪問請求,程序首先需要對后一個元素即第4個元素,也就是下標為3的元素清零;在1 000 000 002s內,任何一個請求如果發現下標為3的元素不為0,則都會將原子變量3清零,并記錄清零的時間。
這時程序可以對第3個元素即下標為2的元素,進行累加并判斷是否達到閾值,如果達到閾值,則拒絕請求,否則請求通過;同時,打印本次及之前3秒的數據訪問量,打印結果如下。
當前:1次,前1s:302次,前2s:201次,前3s:518次
然而,如果當前秒一直沒有請求量,下一秒的計數器始終不能清零,則下一秒的請求到達后要首先清零再使用,并更新清零時間。
在下一秒的請求到達后,若檢查到當前秒對應的原子變量計數器不為0,而且最后的清零時間不是上一秒,則先對當前秒的計數器清零,再進行累加操作,這避免發生上一秒無請求的場景,或者上一秒的請求由于線程調度延遲而沒有清零下一秒的場景,后面這種場景發生的概率較小。
另外一種實現計數器的簡單方法是單獨啟動一個線程,每隔一定的時間間隔執行對下一秒的原子變量計數器清零操作,這個時間間隔必須小于計數時間間隔。
2)令牌筒
令牌筒是一個流行的實現限流的技術方案,它通過一個線程在單位時間內生產固定數量的令牌,然后把令牌放入隊列,每次請求調用需要從桶中拿取一個令牌,拿到令牌后才有資格執行請求調用,否則只能等待拿到令牌再執行,或者直接丟棄。
令牌筒的結構如圖1-32所示。
?
?
圖1-32?
3)信號量
限流類似于生活中的漏洞,無論倒入多少油,下面有漏管的流量是有限的,實際上我們在應用層使用的信號量也可以實現限流。?
使用信號量的示例如下:
4. 失效轉移模式
若微服務架構中發生了熔斷和限流,則該如何處理被拒絕的請求呢?解決這個問題的模式叫作失效轉移模式,通常分為下面幾種。
-
采用快速失敗的策略,直接返回使用方錯誤,讓使用方知道發生了問題并自行決定后續處理。
-
是否有備份服務,如果有備份服務,則迅速切換到備份服務。
-
失敗的服務有可能是某臺機器有問題,而不是所有機器有問題,例如OOM問題,在這種情況下適合使用failover策略,采用重試的方法來解決,但是這種方法要求服務提供者的服務實現了冪等性。
-
轉載于:https://www.cnblogs.com/davidwang456/articles/9276960.html
總結
- 上一篇: 基于 Spring Cloud 的服务治
- 下一篇: 微服务实践分享(8) 控制调用中心