1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        10張圖帶你徹底搞懂限流、熔斷、服務(wù)降級(jí)

        共 6624字,需瀏覽 14分鐘

         ·

        2021-06-02 20:41


        在分布式系統(tǒng)中,如果某個(gè)服務(wù)節(jié)點(diǎn)發(fā)生故障或者網(wǎng)絡(luò)發(fā)生異常,都有可能導(dǎo)致調(diào)用方被阻塞等待,如果超時(shí)時(shí)間設(shè)置很長,調(diào)用方資源很可能被耗盡。這又導(dǎo)致了調(diào)用方的上游系統(tǒng)發(fā)生資源耗盡的情況,最終導(dǎo)致系統(tǒng)雪崩。

        如下圖:如果D服務(wù)發(fā)生了故障不能響應(yīng),B服務(wù)調(diào)用D時(shí)只能阻塞等待。假如B服務(wù)調(diào)用D服務(wù)設(shè)置超時(shí)時(shí)間是10秒,請(qǐng)求速率是每秒100個(gè),那10秒內(nèi)就會(huì)有1000個(gè)請(qǐng)求線程被阻塞等待,如果B的線程池大小設(shè)置1000,那B系統(tǒng)因?yàn)榫€程資源耗盡已經(jīng)不能對(duì)外提供服務(wù)了。而這又影響了入口系統(tǒng)A的服務(wù),最終導(dǎo)致系統(tǒng)全面崩潰。

        提高系統(tǒng)的整體容錯(cuò)能力是防止系統(tǒng)雪崩的有效手段。

        Martin FowlerJames Lewis的文章 《Microservices: a definition of this new architectural term》[1]中,提出了微服務(wù)的9個(gè)特征,其中一個(gè)是容錯(cuò)設(shè)計(jì)。

        要防止系統(tǒng)發(fā)生雪崩,就必須要有容錯(cuò)設(shè)計(jì)。如果遇到突增流量,一般的做法是對(duì)非核心業(yè)務(wù)功能采用熔斷和服務(wù)降級(jí)的措施來保護(hù)核心業(yè)務(wù)功能正常服務(wù),而對(duì)于核心功能服務(wù),則需要采用限流的措施。

        今天我們來聊一聊系統(tǒng)容錯(cuò)中的限流、熔斷和服務(wù)降級(jí)。

        1 限流

        當(dāng)系統(tǒng)的處理能力不能應(yīng)對(duì)外部請(qǐng)求的突增流量時(shí),為了不讓系統(tǒng)奔潰,必須采取限流的措施。

        1.1 限流指標(biāo)

        1.1.1 TPS

        系統(tǒng)吞吐量是衡量系統(tǒng)性能的關(guān)鍵指標(biāo),按照事務(wù)的完成數(shù)量來限流是最合理的。

        但是對(duì)實(shí)操性來說,按照事務(wù)來限流并不現(xiàn)實(shí)。在分布式系統(tǒng)中完成一筆事務(wù)需要多個(gè)系統(tǒng)的配合。比如我們?cè)陔娚滔到y(tǒng)購物,需要訂單、庫存、賬戶、支付等多個(gè)服務(wù)配合完成,有的服務(wù)需要異步返回,這樣完成一筆事務(wù)花費(fèi)的時(shí)間可能會(huì)很長。如果按照TPS來進(jìn)行限流,時(shí)間粒度可能會(huì)很大大,很難準(zhǔn)確評(píng)估系統(tǒng)的響應(yīng)性能。

        1.1.2 HPS

        每秒請(qǐng)求數(shù),指每秒鐘服務(wù)端收到客戶端的請(qǐng)求數(shù)量。

        ?

        如果一個(gè)請(qǐng)求完成一筆事務(wù),那TPSHPS是等同的。但在分布式場景下,完成一筆事務(wù)可能需要多次請(qǐng)求,所以TPSHPS指標(biāo)不能等同看待。

        ?

        1.1.3 QPS

        服務(wù)端每秒能夠響應(yīng)的客戶端查詢請(qǐng)求數(shù)量。

        ?

        如果后臺(tái)只有一臺(tái)服務(wù)器,那HPSQPS是等同的。但是在分布式場景下,每個(gè)請(qǐng)求需要多個(gè)服務(wù)器配合完成響應(yīng)。

        ?
        ?

        目前主流的限流方法多采用HPS作為限流指標(biāo)。

        ?

        1.2 限流方法

        1.2.1 流量計(jì)數(shù)器

        這是最簡單直接的方法,比如限制每秒請(qǐng)求數(shù)量100,超過100的請(qǐng)求就拒絕掉。

        但是這個(gè)方法存在2個(gè)明顯的問題:

        • 單位時(shí)間(比如1s)很難把控,如下圖:這張圖上,從下面時(shí)間看,HPS沒有超過100,但是從上面看HPS超過100了。

        • 有一段時(shí)間流量超了,也不一定真的需要限流,如下圖,系統(tǒng)HPS限制50,雖然前3s流量超了,但是如果讀超時(shí)時(shí)間設(shè)置為5s,并不需要限流。

        1.2.2 滑動(dòng)時(shí)間窗口

        滑動(dòng)時(shí)間窗口算法是目前比較流行的限流算法,主要思想是把時(shí)間看做是一個(gè)向前滾動(dòng)的窗口,如下圖:開始的時(shí)候,我們把t1~t5看做一個(gè)時(shí)間窗口,每個(gè)窗口1s,如果我們定的限流目標(biāo)是每秒50個(gè)請(qǐng)求,那t1~t5這個(gè)窗口的請(qǐng)求總和不能超過250個(gè)。

        這個(gè)窗口是滑動(dòng)的,下一秒的窗口成了t2~t6,這時(shí)把t1時(shí)間片的統(tǒng)計(jì)拋棄,加入t6時(shí)間片進(jìn)行統(tǒng)計(jì)。這段時(shí)間內(nèi)的請(qǐng)求數(shù)量也不能超過250個(gè)。

        滑動(dòng)時(shí)間窗口的優(yōu)點(diǎn)是解決了流量計(jì)數(shù)器算法的缺陷,但是也有2個(gè)問題:

        • 流量超過就必須拋棄或者走降級(jí)邏輯
        • 對(duì)流量控制不夠精細(xì),不能限制集中在短時(shí)間內(nèi)的流量,也不能削峰填谷

        1.2.3 漏桶算法

        漏桶算法的思想如下圖:在客戶端的請(qǐng)求發(fā)送到服務(wù)器之前,先用漏桶緩存起來,這個(gè)漏桶可以是一個(gè)長度固定的隊(duì)列,這個(gè)隊(duì)列中的請(qǐng)求均勻的發(fā)送到服務(wù)端。

        如果客戶端的請(qǐng)求速率太快,漏桶的隊(duì)列滿了,就會(huì)被拒絕掉,或者走降級(jí)處理邏輯。這樣服務(wù)端就不會(huì)受到突發(fā)流量的沖擊。

        漏桶算法的優(yōu)點(diǎn)是實(shí)現(xiàn)簡單,可以使用消息隊(duì)列來削峰填谷。

        但是也有3個(gè)問題需要考慮:

        • 漏桶的大小,如果太大,可能給服務(wù)端帶來較大處理壓力,太小可能會(huì)有大量請(qǐng)求被丟棄。
        • 漏桶給服務(wù)端的請(qǐng)求發(fā)送速率。
        • 使用緩存請(qǐng)求的方式,會(huì)使請(qǐng)求響應(yīng)時(shí)間變長。
        ?

        漏桶大小和發(fā)送速率這2個(gè)值在項(xiàng)目上線初期都會(huì)根據(jù)測(cè)試結(jié)果選擇一個(gè)值,但是隨著架構(gòu)的改進(jìn)和集群的伸縮,這2個(gè)值也會(huì)隨之發(fā)生改變。

        ?

        1.2.4 令牌桶算法

        令牌桶算法就跟病人去醫(yī)院看病一樣,找醫(yī)生之前需要先掛號(hào),而醫(yī)院每天放的號(hào)是有限的。當(dāng)天的號(hào)用完了,第二天又會(huì)放一批號(hào)。

        算法的基本思想就是周期性的執(zhí)行下面的流程:客戶端在發(fā)送請(qǐng)求時(shí),都需要先從令牌桶中獲取令牌,如果取到了,就可以把請(qǐng)求發(fā)送給服務(wù)端,取不到令牌,就只能被拒絕或者走服務(wù)降級(jí)的邏輯。如下圖:

        ?

        令牌桶算法解決了漏桶算法的問題,而且實(shí)現(xiàn)并不復(fù)雜,使用信號(hào)量就可以實(shí)現(xiàn)。在實(shí)際限流場景中使用最多,比如googleguava中就實(shí)現(xiàn)了令牌桶算法限流,感興趣可以研究一下。

        ?

        1.2.5 分布式限流

        如果在分布式系統(tǒng)場景下,上面介紹的4種限流算法是否還適用呢?

        以令牌桶算法為例,假如在電商系統(tǒng)中客戶下了一筆訂單,如下圖:如果我們把令牌桶單獨(dú)保存在一個(gè)地方(比如redis中)供整個(gè)分布式系統(tǒng)用,那客戶端在調(diào)用組合服務(wù),組合服務(wù)調(diào)用訂單、庫存和賬戶服務(wù)都需要跟令牌桶交互,交互次數(shù)明顯增加了很多。

        有一種改進(jìn)就是客戶端調(diào)用組合服務(wù)之前首先獲取四個(gè)令牌,調(diào)用組合服務(wù)時(shí)減去一個(gè)令牌并且傳遞給組合服務(wù)三個(gè)令牌,組合服務(wù)調(diào)用下面三個(gè)服務(wù)時(shí)依次消耗一個(gè)令牌。

        1.2.6 hystrix限流

        hystrix可以使用信號(hào)量和線程池來進(jìn)行限流。

        1.2.6.1 信號(hào)量限流

        hystrix可以使用信號(hào)量進(jìn)行限流,比如在提供服務(wù)的方法上加下面的注解。這樣只能有20個(gè)并發(fā)線程來訪問這個(gè)方法,超過的就被轉(zhuǎn)到了errMethod這個(gè)降級(jí)方法。

        @HystrixCommand(
         commandProperties= {
           @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE"),
           @HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests", value="20")
         },
         fallbackMethod = "errMethod"
        )

        1.2.6.2 線程池限流

        hystrix也可以使用線程池進(jìn)行限流,在提供服務(wù)的方法上加下面的注解,當(dāng)線程數(shù)量

        @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")
            },
            threadPoolKey = "createOrderThreadPool",
            threadPoolProperties = {
                    @HystrixProperty(name = "coreSize", value = "20"),
           @HystrixProperty(name = "maxQueueSize", value = "100"),
                    @HystrixProperty(name = "maximumSize", value = "30"),
                    @HystrixProperty(name = "queueSizeRejectionThreshold", value = "120")
            },
            fallbackMethod = "errMethod"
        )
        ?

        這里要注意:在java的線程池中,如果線程數(shù)量超過coreSize,創(chuàng)建線程請(qǐng)求會(huì)優(yōu)先進(jìn)入隊(duì)列,如果隊(duì)列滿了,就會(huì)繼續(xù)創(chuàng)建線程直到線程數(shù)量達(dá)到maximumSize,之后走拒絕策略。但在hystrix配置的線程池中多了一個(gè)參數(shù)queueSizeRejectionThreshold,如果queueSizeRejectionThreshold < maxQueueSize,隊(duì)列數(shù)量達(dá)到queueSizeRejectionThreshold就會(huì)走拒絕策略了,因此maximumSize失效了。如果queueSizeRejectionThreshold > maxQueueSize,隊(duì)列數(shù)量達(dá)到maxQueueSize時(shí),maximumSize是有效的,系統(tǒng)會(huì)繼續(xù)創(chuàng)建線程直到數(shù)量達(dá)到maximumSize。Hytrix線程池設(shè)置坑[2]

        ?

        2 熔斷

        相信大家對(duì)斷路器并不陌生,它就相當(dāng)于一個(gè)開關(guān),打開后可以阻止流量通過。比如保險(xiǎn)絲,當(dāng)電流過大時(shí),就會(huì)熔斷,從而避免元器件損壞。

        服務(wù)熔斷是指調(diào)用方訪問服務(wù)時(shí)通過斷路器做代理進(jìn)行訪問,斷路器會(huì)持續(xù)觀察服務(wù)返回的成功、失敗的狀態(tài),當(dāng)失敗超過設(shè)置的閾值時(shí)斷路器打開,請(qǐng)求就不能真正地訪問到服務(wù)了。

        為了更好地理解,我畫了下面的時(shí)序圖:

        ?

        可以參考Martin Fowler的論文《CircuitBreaker》[3]。

        ?

        2.1 斷路器的狀態(tài)

        斷路器有3種狀態(tài):

        • CLOSED:默認(rèn)狀態(tài)。斷路器觀察到請(qǐng)求失敗比例沒有達(dá)到閾值,斷路器認(rèn)為被代理服務(wù)狀態(tài)良好。
        • OPEN:斷路器觀察到請(qǐng)求失敗比例已經(jīng)達(dá)到閾值,斷路器認(rèn)為被代理服務(wù)故障,打開開關(guān),請(qǐng)求不再到達(dá)被代理的服務(wù),而是快速失敗。
        • HALF OPEN:斷路器打開后,為了能自動(dòng)恢復(fù)對(duì)被代理服務(wù)的訪問,會(huì)切換到半開放狀態(tài),去嘗試請(qǐng)求被代理服務(wù)以查看服務(wù)是否已經(jīng)故障恢復(fù)。如果成功,會(huì)轉(zhuǎn)成CLOSED狀態(tài),否則轉(zhuǎn)到OPEN狀態(tài)。

        斷路器的狀態(tài)切換圖如下:

        2.2 需要考慮的問題

        使用斷路器需要考慮一些問題:

        • 針對(duì)不同的異常,定義不同的熔斷后處理邏輯。
        • 設(shè)置熔斷的時(shí)長,超過這個(gè)時(shí)長后切換到HALF OPEN進(jìn)行重試。
        • 記錄請(qǐng)求失敗日志,供監(jiān)控使用。
        • 主動(dòng)重試,比如對(duì)于connection timeout造成的熔斷,可以用異步線程進(jìn)行網(wǎng)絡(luò)檢測(cè),比如telenet,檢測(cè)到網(wǎng)絡(luò)暢通時(shí)切換到HALF OPEN進(jìn)行重試。
        • 補(bǔ)償接口,斷路器可以提供補(bǔ)償接口讓運(yùn)維人員手工關(guān)閉。
        • 重試時(shí),可以使用之前失敗的請(qǐng)求進(jìn)行重試,但一定要注意業(yè)務(wù)上是否允許這樣做。

        2.3 使用場景

        • 服務(wù)故障或者升級(jí)時(shí),讓客戶端快速失敗
        • 失敗處理邏輯容易定義
        • 響應(yīng)耗時(shí)較長,客戶端設(shè)置的read timeout會(huì)比較長,防止客戶端大量重試請(qǐng)求導(dǎo)致的連接、線程資源不能釋放

        3 服務(wù)降級(jí)

        前面講了限流和熔斷,相比來說,服務(wù)降級(jí)是站在系統(tǒng)全局的視角來考慮的。

        在服務(wù)發(fā)生熔斷后,一般會(huì)讓請(qǐng)求走事先配置的處理方法,這個(gè)處理方法就是一個(gè)降級(jí)邏輯。

        服務(wù)降級(jí)是對(duì)非核心、非關(guān)鍵的服務(wù)進(jìn)行降級(jí)。

        3.1 使用場景

        • 服務(wù)處理異常,把異常信息直接反饋給客戶端,不再走其他邏輯
        • 服務(wù)處理異常,把請(qǐng)求緩存下來,給客戶端返回一個(gè)中間態(tài),事后再重試緩存的請(qǐng)求
        • 監(jiān)控系統(tǒng)檢測(cè)到突增流量,為了避免非核心業(yè)務(wù)功能耗費(fèi)系統(tǒng)資源,關(guān)閉這些非核心功能
        • 數(shù)據(jù)庫請(qǐng)求壓力大,可以考慮返回緩存中的數(shù)據(jù)
        • 對(duì)于耗時(shí)的寫操作,可以改為異步寫
        • 暫時(shí)關(guān)閉跑批任務(wù),以節(jié)省系統(tǒng)資源

        3.2 使用hystrix降級(jí)

        3.2.1 異常降級(jí)

        hystrix降級(jí)時(shí)可以忽略某個(gè)異常,在方法上加上@HystrixCommand注解:

        下面的代碼定義降級(jí)方法是errMethod,對(duì)ParamErrorExceptionBusinessTypeException這兩個(gè)異常不做降級(jí)處理。

        @HystrixCommand(
         fallbackMethod = "errMethod",
         ignoreExceptions = {ParamErrorException.classBusinessTypeException.class}
        )

        3.2.2 調(diào)用超時(shí)降級(jí)

        專門針對(duì)調(diào)用第三方接口超時(shí)降級(jí)。

        下面的方法是調(diào)用第三方接口3秒未收到響應(yīng)就降級(jí)到errMethod方法。

        @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(name="execution.timeout.enabled", value="true"),
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="3000"),
            },
            fallbackMethod = "errMethod"
        )

        總結(jié)

        限流、熔斷和服務(wù)降級(jí)是系統(tǒng)容錯(cuò)的重要設(shè)計(jì)模式,從一定意義上講限流和熔斷也是一種服務(wù)降級(jí)的手段。

        熔斷和服務(wù)降級(jí)主要是針對(duì)非核心業(yè)務(wù)功能,而核心業(yè)務(wù)如果流程超過預(yù)估的峰值,就需要進(jìn)行限流。

        對(duì)于限流,選擇合理的限流算法很重要,令牌桶算法優(yōu)勢(shì)很明顯,也是使用最多的限流算法。

        在系統(tǒng)設(shè)計(jì)的時(shí)候,這些模式需要配合業(yè)務(wù)量的預(yù)估、性能測(cè)試的數(shù)據(jù)進(jìn)行相應(yīng)閾值的配置,而這些閾值最好保存在配置中心,方便實(shí)時(shí)修改。

        「原創(chuàng)不易,點(diǎn)贊、再看、轉(zhuǎn)發(fā)是對(duì)我最大的支持」

        Reference

        [1]

        Microservices: a definition of this new architectural term: https://time.geekbang.org/column/article/312390

        [2]

        Hytrix線程池設(shè)置坑: https://zhuanlan.zhihu.com/p/161522189

        [3]

        CircuitBreaker: https://martinfowler.com/bliki/CircuitBreaker.html

        瀏覽 59
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            午夜秋霞无码鲁丝A片一级 | 强行扒开双腿猛烈进入老师 | 日本泡妞xxxxxxxx69 | 美女被操网站免费 | 麻豆系列在线观看 | 免看一级a一片成人久久最新章节 | veronica高潮抽搐aulva | 久久精品免费看 | 男女互操软件 | 国产高清码 在线观看 |