微服務架構是將單個應用程序被劃分紅各類小而鏈接的服務,每個服務完成一個單一的業務功能。相對於傳統的單體服務,微服務具備隔離性、技術異構性、可擴展性以及簡化部署等優勢。一般一個應用由多個微服務組成,微服務之間的數據交互須要經過遠過程調用的方式完成。html
下圖是一個微服務之間互相調用的場景:java
微服務A調用微服務B、C和D,微服務C又調用微服務E。假設某一時刻,微服務E變爲不可用。微服務C須要等待微服務E返回結果,因而請求就會逐漸堆積在微服務C,造成阻塞。隨着微服務C堆積的請求不斷增長,微服務A也會隨之慢慢阻塞。由於服務器所能支撐的併發數有限,因此最終會耗盡服務器資源,從而致使調用鏈條上更多的微服務不可用,造成雪崩效應。這種由一個服務崩潰致使整條服務鏈崩潰的狀況,咱們就稱之爲服務雪崩。git
在微服務架構中,一般有兩種狀況會致使服務雪崩:github
突發性的訪問量劇增,超出了服務處理極限算法
調用鏈條上某個服務出現故障或者響應慢(延遲)後端
針對以上這兩種狀況,產生了對應的解決方案:服務限流和服務熔斷。api
服務限流是指在必定時間段內限制服務的請求量以保護系統,主要用於防止突發流量而致使的服務崩潰,好比秒殺、搶購、雙十一等場景,也能夠用於安全目的,好比應對外部暴力攻擊。安全
經常使用的限流算法有如下幾種:服務器
計數器算法網絡
經過維護一個內部計數器,對一段時間的服務請求進行累計,判斷計數器是否達到預先設定的閾值。若是沒有達到閾值,就容許請求經過,而且計數器加1;若是達到閾值,則拒絕服務,拋棄請求。進入下一個計時週期後,計數器清零,從新計數。
計數器算法是限流算法中最簡單的算法,缺點是有突刺現象,不只請求經過的速率不均勻,並且請求輸出的速率也不均勻,對後續處理的併發要求比較高。好比:設定服務週期爲1秒,請求的上限閾值爲1000。若是前1ms內已經收到1000個請求,那麼剩下的時間都只能拒絕,並且後端服務須要併發處理1000個請求。
漏桶算法
漏桶算法的原理能夠這樣理解,將服務請求想象成流入漏桶的水,漏桶中的水以恆定的速率從桶底流出,當流入漏桶的水速度過快,超過了漏桶容量時,則直接溢出。因此,漏桶算法可以控制服務請求按照固定速率均勻輸出,平滑突發流量,實現流量整形,爲後續處理提供一個穩定的流量。可是,漏桶算法沒法控制請求按照必定的速率均勻輸入。
令牌桶算法
令牌桶算法是速率限制(Rate Limiting)和流量整形(Traffic Shaping)中最常使用的一種算法。典型狀況下,令牌桶算法用來控制發送到網絡上的數據的數目,並容許突發數據的發送。
首先設定一個能夠存放固定數量的令牌桶,使用某種機制以恆定的速度產生令牌。每次請求調用時,都必須去桶中獲取令牌,只有拿到令牌,才能放行,不然只能等待可用的令牌,或者直接拒絕。若是桶中的令牌消耗的速度小於產生的速度,令牌就會不斷地增多,直至填滿,再產生的令牌就會從桶中溢出。
因此,令牌桶算法既能夠控制請求均勻輸入的速度,又能夠控制請求的均勻輸出速率。
咱們在各類場景下都會接觸到熔斷這兩個字。高壓電路中,若是某處電壓太高,熔斷器就會熔斷,對電路進行保護。股票交易中,若是股票漲跌幅過大,也會採用熔斷機制,暫停交易,來控制交易風險。
一樣,在微服務架構中,熔斷機制也是起着相似的做用。當調用鏈路中的某個微服務長時間不可用或者有延遲,響應過慢,系統就會熔斷對該節點微服務的調用,快速返回錯誤信息。當監控到該微服務正常工做後,再次恢復該調用鏈路。
服務熔斷和服務限流做爲微服務架構中做爲服務治理的重要手段,在不少開源框架或者產品中都包含了此類功能。好比阿里dubbo,Netflix Hystrix,go-micro,go-kit等。
Hystrix是Netflix公司的開源項目,它是一個延遲和故障容錯庫,旨在隔離對遠程系統、服務和第三方庫的訪問點,防止級聯故障,並在沒法避免發生故障的複雜分佈式系統中實現了彈性。
Hystrix項目使用了java語言開發,代碼託管地址爲:https://github.com/Netflix/Hystrix。另外,有人使用go語言將該項目進行了移植,代碼託管地址爲:https://github.com/afex/hystrix-go/hystrix。
Hystrix能夠作到如下事情:
Hystrix 能使你的系統在出現依賴服務失效的時候,經過隔離系統所依賴的服務,防止服務級聯失敗,同時提供失敗回退機制,更優雅地應對失效,並使你的系統能更快地從異常中恢復。
使用Hystrix 很是簡單:
package main import ( "github.com/afex/hystrix-go/hystrix" "log" ) func main() { // 每一類微服務、遠程系統、第三方庫的調用都被包裝爲一個命令, // 調用以前須要先行設置相關的配置信息 hystrix.ConfigureCommand( "ServiceA", // 命令名稱 hystrix.CommandConfig{ Timeout: 1000, // 超時時間設置(毫秒) MaxConcurrentRequests: 1, // 最大併發請求數 ErrorPercentThreshold: 50, // 錯誤率閾值,超過閾值將熔斷服務 SleepWindow: 5000, // 服務熔斷後,過多長時間,熔斷器再次檢測是否開啓(毫秒) RequestVolumeThreshold: 20, // 服務熔斷前,所需的最小請求量,請求閾值 熔斷器是否打開首先要知足這個條件;這裏的設置表示至少有5個請求才進行ErrorPercentThreshold錯誤百分比計算 }) // 使用hystrix調用遠程服務,並根據命令名稱啓用ConfigureCommand中設置的參數 _ = hystrix.Do( "ServiceA", // 命令名稱 // 運行函數 func() error { // 調用遠程服務 log.Println("invoke a remote service") return nil }, // 失敗回退函數 func(err error) error { log.Println("fall back") return err }, ) }
注:
本文所有源代碼位於:https://github.com/wangshizebin/micro-service
本文時候用的開發工具爲:goland 來自 嗖嗖下載