Spring Cloud Hystrix 熔斷器(五)

序言

感受hystrix很精彩,文檔講的也很好,這篇總結到哪裏是哪裏吧git

寫Hystrix以前,咱們先簡單的說說熔斷器,和限流,這樣你看完以後,就能夠很容易理解Hystrixgithub

熔斷器

熔斷器模式源於Martin Fowler的Circuit Breaker一文。「熔斷器」自己是一種開關裝置,用於在電路上保護線路過載,當線路中有電器發生短路時,「熔斷器」可以及時的切斷故障電路,防止發生過載、發熱、甚至起火等嚴重後果。算法

熔斷器設計中有三種狀態,生生世世,循環往復。spring

  1. closed(關閉狀態,流量能夠正常進入)
  2. open(即熔斷狀態,一旦錯誤達到閾值,熔斷器將打開,拒絕全部流量)
  3. half-open(半開狀態,open狀態持續一段時間後將自動進入該狀態,從新接收流量,一旦請求失敗,從新進入open狀態,但若是成功數量達到閾值,將進入closed狀態)

總體流程見下圖:數據庫

CLOSED關閉狀態容許流量經過後端

OPEN打開狀態:不容許流量經過,即處於降級狀態,走降級邏輯。緩存

HALF_OPEN半開狀態:容許某些流量經過,並關注這些流量的結果,若是出現超時、異常等狀況,將進入OPEN狀態,若是成功,那麼將進入CLOSED狀態服務器

在分佈式架構中,熔斷器模式的做用也是相似的,當某個服務單元發生故障(相似用電器發生短路)以後,經過斷路器的故障監控(相似熔斷保險絲),向調用方返回一個錯誤響應,而不是長時間的等待。這樣就不會使得線程因調用故障服務被長時間佔用不釋放,避免了故障在分佈式系統中的蔓延。網絡

限流

在開發高併發系統時,有不少手段保護系統,好比緩存降級限流。緩存的目的是提高系統訪問速度和增大系統處理能力,可謂是抗高併發的銀彈。而降級是當服務出問題或者影響到核心流程的性能,須要暫時屏蔽掉,待高峯過去或者問題解決後再打開的場景。而有些場景並不能用緩存和降級來解決,好比稀缺資源(秒殺、搶購)、寫服務(如評論、下單)、頻繁的複雜查詢(評論的最後幾頁)等。所以,須要有一種手段來限制這些場景下的併發/請求量,這種手段就是限流。架構

限流的目的是經過對併發訪問/請求進行限速或者一個時間窗口內的請求進行限速來保護系統,一旦達到限速速率則能夠拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊或等待(好比秒殺、評論、下單)、降級(返回兜底數據或者默認數據,如商品詳情頁庫存默認有貨)。在壓測時,咱們能找出每一個系統的處理峯值,而後經過設定峯值閾值,當系統過載時,經過拒絕過載的請求來保障系統可用。另外,也能夠根據系統的吞吐量、響應時間、可用率來動態調整限流閾值。

通常開發高併發系統場景的限流有:限制總併發數(好比數據庫鏈接池、線程池)、限制瞬時併發數(如Nginx的limit_conn模塊,用來限制瞬間併發鏈接數)、限制時間窗口內的平均速率(如Guava的RateLimiter、Nginx的limit_req模塊,用來限制每秒的平均速率),以及限制遠程接口調用速率、限制MQ的消費速率等。另外還能夠根據網絡鏈接數、網絡流量、CPU或內存負載等來限流。

限流算法

常見的限流算法有:令牌桶、漏桶。計數器也能夠用來進行粗暴限流實現。

令牌桶算法

令牌桶算法,是一個存放固定容量令牌的桶,按照固定速率往桶裏添加令牌。令牌桶算法的描述以下:

  • 假設限制2r/s,則按照500毫秒的固定速率往桶內添加令牌。
  • 桶中最多存放b個令牌,當桶滿時,新添加的令牌會被丟棄或拒絕。
  • 當一個n個字節大小的數據包到達,將從桶中刪除n個令牌,接着數據包被髮送到網絡上。
  • 若是桶中的令牌不足n個,則不會刪除令牌,且該數據包被限流(要麼丟棄,要麼在緩衝區等待)。

漏桶算法

漏桶做爲計量工具時,能夠用於流量整形和流量控制,漏桶算法的描述以下:

  • 一個固定容量的漏桶,按照常量固定速率流出水滴。
  • 若是桶是空的,則不需流出水滴。
  • 能夠以任意速率流入水滴到漏桶。
  • 若是流入水滴超過了桶的容量,則流入的水滴溢出了(被丟棄),而漏桶容量是不變的。

常見的限流方式有:限制總併發數(數據庫鏈接池、線程池)、限制瞬時併發數(如Nginx的limit_conn模塊)、限制時間窗口的平均速率(如Guava的RateLimiter、Nginx的limit_req模塊)、限制遠程接口的調用速率限制MQ的消費速率等。從應用的層面上來說,又能夠分爲:接入層限流應用層限流分佈式限流等。

Hystrix是什麼

這一節方便閱讀,我都抄下來來,具體看文檔Hystrix:https://github.com/Netflix/Hystrix/wiki

在分佈式環境中,許多服務依賴項中的一些不可避免地會失敗。Hystrix是一個庫,可經過添加延遲容錯和容錯邏輯來幫助您控制這些分佈式服務之間的交互。Hystrix經過隔離服務之間的訪問點,阻止它們之間的級聯故障以及提供後備選項來實現這一目標,全部這些均可以提升系統的總體彈性。

Hystrix旨在執行如下操做:

  • 經過第三方客戶端庫訪問(一般經過網絡)依賴關係,以防止和控制延遲和故障。
  • 在複雜的分佈式系統中中止級聯故障。
  • 快速失敗並迅速恢復。
  • 在可能的狀況下,後退並優雅地降級。
  • 實現近實時監控,警報和操做控制。

複雜分佈式體系結構中的應用程序有許多依賴項,每一個依賴項在某些時候都不可避免地會失敗。若是主機應用程序沒有與這些外部故障隔離,那麼它有可能被他們拖垮。

例如,對於一個依賴於30個服務的應用程序,每一個服務都有99.99%的正常運行時間,你能夠指望以下:

99.9930 = 99.7% 可用

也就是說一億個請求的0.03% = 3000000 會失敗

若是一切正常,那麼每月有2個小時服務是不可用的

現實一般是更糟糕 


當一切正常時,請求看起來是這樣的:

當其中有一個系統有延遲時,它可能阻塞整個用戶請求:

在高流量的狀況下,一個後端依賴項的延遲可能致使全部服務器上的全部資源在數秒內飽和(PS:意味着後續再有請求將沒法當即提供服務)

當您使用Hystrix來包裝每一個底層依賴項時,上圖中顯示的體系結構將更改成相似於下圖。每一個依賴項彼此隔離,在發生延遲時能夠飽和的資源受到限制,而且在回退邏輯中涵蓋,該邏輯決定了在依賴項中發生任何類型的故障時要作出的響應:

Feign調用使用Hystrix示例

首先,前幾節的環境,都有啊,沒有或須要的去看我前幾篇文章吧

pom.xml

 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

feign調用接口

@FeignClient(name = "trade-promotion", fallback = PromotionClientFallback.class)
public interface PromotionClient {
    @RequestMapping(value = "/Promotion/delete", method = RequestMethod.GET)
    String releasePromotion(@RequestParam int orderID);
}

fallback類

@Component
public class PromotionClientFallback implements PromotionClient {
    @Override
    public String releasePromotion(@RequestParam int orderID) {
        return "hello ,fallback !";
    }
}

調用

@RestController
@RequestMapping(value = "/promotion", method = RequestMethod.GET)
public class PromotionController {
    @Autowired
    PromotionClient promotionClient;

    @RequestMapping(value = "/delete")
    public String delete(@RequestParam int orderID) {
        return promotionClient.releasePromotion(orderID);
    }
}

配置文件

#hystrix
feign.hystrix.enabled=true

好啦,能夠啦.說下,就是若是遠程調用接口異常,會執行Fallback返回 "hello ,fallback !";

若是你想知道爲何失敗,失敗的緣由

@Component
public class PromotionClientFallbackFactory implements FallbackFactory<PromotionClient> {
    @Override
    public PromotionClient create(Throwable cause) {
        return new PromotionClient() {
            @Override
            public String releasePromotion(int orderID) {
                return "fallback:orderid=" + orderID + ",message:" + cause.getMessage();
            }
        };
    }
}
@FeignClient(name = "trade-promotion", fallbackFactory = PromotionClientFallbackFactory.class)
public interface PromotionClient {
    @RequestMapping(value = "/Promotion/delete", method = RequestMethod.GET)
    String releasePromotion(@RequestParam int orderID);
}

這樣也能夠

 

  @HystrixCommand(fallbackMethod = "error")
    public String search(@RequestParam int id) {
        try {
            Thread.sleep(10000);
            return id + "";
        }
        catch (Exception ex)
        {
            return ex.getMessage();
        }

    }
    public String error(int id)
    {
        return  "error"+id;
    }

 

好啦,這樣就ok啦.

Hystrix配置

#hystrix
feign.hystrix.enabled=true
#是否開啓fallback功能,默認爲true
hystrix.command.default.fallback.enabled=true
#開啓hystrix請求超時機制 也能夠設置成永久不超時
hystrix.command.default.execution.timeout.enabled=true
#設置調用者執行的超時時間(單位毫秒),默認:1000
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
#此屬性設置從調用線程容許HystrixCommand.getFallback()方法容許的最大併發請求數
#若是達到最大的併發量,則接下來的請求會被拒絕而且拋出異常.
#默認爲10
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests = 500
#當HystrixCommand.run()使用SEMAPHORE的隔離策略時,設置最大的併發量
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests = 1000
#是否開啓斷路器功能,默認爲true
hystrix.command.default.circuitBreaker.enabled=true
#該屬性設置滾動窗口中將使斷路器跳閘的最小請求數量
#若是此屬性值爲20,則在窗口時間內(如10s內),若是隻收到19個請求且都失敗了,則斷路器也不會開啓。
#默認值:20
hystrix.command.default.circuitBreaker.requestVolumeThreshold=200
#斷路器跳閘後,在此值的時間的內,hystrix會拒絕新的請求,只有過了這個時間斷路器纔會打開閘門
#默認值:5000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=60000
#設置失敗百分比的閾值。若是失敗比率超過這個值,則斷路器跳閘而且進入fallback邏輯
#默認值:50 ,即50%
hystrix.command.default.circuitBreaker=50
#若是設置true,則強制使斷路器進行關閉狀態,此時會容許執行全部請求,不管是否失敗的次數達到circuitBreaker.errorThresholdPercentage值
#默認值:false
hystrix.command.default.circuitBreaker.forceOpe=false
#若是設置true,則強制使斷路器進行關閉狀態,此時會容許執行全部請求,不管是否失敗的次數達到circuitBreaker.errorThresholdPercentage值
#默認值:false
hystrix.command.default.circuitBreaker.forceClosed=false
#設置線程池的core size,這是最大的併發執行數量。默認10
hystrix.threadpool.default.coreSize=500
#最大隊列長度。設置BlockingQueue的最大長度。默認-1。
#若是設置成-1,就會使用SynchronizeQueue。
#若是其餘正整數就會使用LinkedBlockingQueue。
hystrix.threadpool.default.maxQueueSize=1000
#設置拒絕請求的臨界值。只有maxQueueSize爲-1時纔有效。
#設置設個值的緣由是maxQueueSize值運行時不能改變,咱們能夠經過修改這個變量動態修改容許排隊的長度。默認5
hystrix.threadpool.default.queueSizeRejectionThreshold=1000
#設置統計滾動窗口的時間長度,默認值:10000
hystrix.command.default.metrics.rollingStats.timeInMilliseconds=10000
#設置統計滾動窗口的桶數量,
#注意:如下配置必須成立,不然會拋出異常。
#metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0
#如:10000/十、10000/20是正確的配置,可是10000/7錯誤的
#在高併發的環境裏,每一個桶的時間長度建議大於100ms
#默認值:10
hystrix.command.default.metrics.rollingStats.numBuckets=10
#設置執行延遲是否被跟蹤,而且被計算在失敗百分比中。若是設置爲false,則全部的統計數據返回-1
#默認值: true
hystrix.command.default.metrics.rollingPercentile.enabled=true
#此屬性設置統計滾動百分比窗口的持續時間,默認值:60000
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds=60000
#設置統計滾動百分比窗口的桶數量
#注意:如下配置必須成立,不然會拋出異常。
#metrics.rollingPercentile.timeInMilliseconds % metrics.rollingPercentile.numBuckets == 0
#如: 60000/六、60000/60是正確的配置,可是10000/7錯誤的
#在高併發的環境裏,每一個桶的時間長度建議大於1000ms
#默認值:6
hystrix.command.default.metrics.rollingPercentile.numBuckets=6
#此屬性設置每一個桶保存的執行時間的最大值。若是桶數量是100,統計窗口爲10s,若是這10s裏有500次執行,只有最後100次執行會被統計到bucket裏去
#默認值:100
hystrix.command.default.metrics.rollingPercentile.bucketSize=100
#採樣時間間隔
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds=500

總結

多看官放文檔,推薦看下hystrix是如何工做的,很精彩.去吧,再次方便你,學很差就怪本身太忙,沒時間看文檔吧: https://github.com/Netflix/Hystrix/wiki

有時間再把hystrix的監控寫下,今天就這啦,88

相關文章
相關標籤/搜索