天天看點

高并發之——服務降級與熔斷

服務降級

由于爆炸性的流量沖擊,對一些服務進行有政策的放棄,以此緩解系統壓力,保證目前主要業務的正常運作。它主要是針對非正常情況下的應急服務措施:當此時一些業務服務無法執行時,給出一個統一的傳回結果。

降級服務的特征

  1. 原因:整體負荷超出整體負載承受能力。
  2. 目的:保證重要或基本服務正常運作,非重要服務延遲使用或暫停使用
  3. 大小:降低服務粒度,要考慮整體子產品粒度的大小,将粒度控制在合适的範圍内
  4. 可控性:在服務粒度大小的基礎上增加服務的可控性,背景服務開關的功能是一項必要配置(單機可配置檔案,其他可領用資料庫和緩存),可分為手動控制和自動控制。
  5. 次序:一般從外圍延伸服務開始降級,需要有一定的配置項,重要性低的優先降級,比如可以分組設定等級1-10,當服務需要降級到某一個級别時,進行相關配置

降級方式

  1. 延遲服務:比如發表了評論,重要服務,比如在文章中顯示正常,但是延遲給使用者增加積分,隻是放到一個緩存中,等服務平穩之後再執行。
  2. 在粒度範圍内關閉服務(片段降級或服務功能降級):比如關閉相關文章的推薦,直接關閉推薦區
  3. 頁面異步請求降級:比如商品詳情頁上有推薦資訊/配送至等異步加載的請求,如果這些資訊響應慢或者後端服務有問題,可以進行降級;
  4. 頁面跳轉(頁面降級):比如可以有相關文章推薦,但是更多的頁面則直接跳轉到某一個位址
  5. 寫降級:比如秒殺搶購,我們可以隻進行Cache的更新,然後異步同步扣減庫存到DB,保證最終一緻性即可,此時可以将DB降級為Cache。
  6. 讀降級:比如多級緩存模式,如果後端服務有問題,可以降級為隻讀緩存,這種方式适用于對讀一緻性要求不高的場景。

降級預案

在進行降級之前要對系統進行梳理,看看系統是不是可以丢卒保帥;進而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日志級别設定預案:

  1. 一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而逾時,可以自動降級;
  2. 警告:有些服務在一段時間内成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發送告警;
  3. 錯誤:比如可用率低于90%,或者資料庫連接配接池被打爆了,或者通路量突然猛增到系統能承受的最大閥值,此時可以根據情況自動降級或者人工降級;
  4. 嚴重錯誤:比如因為特殊原因資料錯誤了,此時需要緊急人工降級。

服務降級分類

  1. 降級按照是否自動化可分為:自動開關降級(逾時、失敗次數、故障、限流)和人工開關降級(秒殺、電商大促等)。
  2. 降級按照功能可分為:讀服務降級、寫服務降級。
  3. 降級按照處于的系統層次可分為:多級降級。

自動降級分類

  1. 逾時降級:主要配置好逾時時間和逾時重試次數和機制,并使用異步機制探測回複情況
  2. 失敗次數降級:主要是一些不穩定的api,當失敗調用次數達到一定閥值自動降級,同樣要使用異步機制探測回複情況
  3. 故障降級:比如要調用的遠端服務挂掉了(網絡故障、DNS故障、http服務傳回錯誤的狀态碼、rpc服務抛出異常),則可以直接降級。降級後的處理方案有:預設值(比如庫存服務挂了,傳回預設現貨)、兜底資料(比如廣告挂了,傳回提前準備好的一些靜态頁面)、緩存(之前暫存的一些緩存資料)
  4. 限流降級

    當我們去秒殺或者搶購一些限購商品時,此時可能會因為通路量太大而導緻系統崩潰,此時開發者會使用限流來進行限制通路量,當達到限流閥值,後續請求會被降級;降級後的處理方案可以是:排隊頁面(将使用者導流到排隊頁面等一會重試)、無貨(直接告知使用者沒貨了)、錯誤頁(如活動太火爆了,稍後重試)

​​參考引用文章​​

服務降級需考慮的問題

  1. 核心服務或非核心服務。
  2. 是否支援降級,及其降級政策。
  3. 業務放通場景,極其政策。

Hystrix元件

Hystrix流程

服務降級通常可以通過使用該組建完成。

  • 在通過第三方用戶端通路(通常通過網絡)依賴服務出現高延遲或失敗時,為系統提供保護和控制。
  • 在分布式系統中防止級聯失敗。
  • 快速失敗(Fail-fast)同時能快速恢複。
  • 提供失敗回退(Fallback)和優雅的服務降級機制。
高并發之——服務降級與熔斷

流程說明:

  1. 每次調用建立一個新的HystrixCommand,把依賴調用封裝在run()方法中.
  2. 執行execute()/queue做同步或異步調用.
  3. 判斷熔斷器(circuit-breaker)是否打開,如果打開跳到步驟8,進行降級政策,如果關閉進入步驟.
  4. 判斷線程池/隊列/信号量是否跑滿,如果跑滿進入降級步驟8,否則繼續後續步驟.
  5. 調用HystrixCommand的run方法.運作依賴邏輯

    a: 依賴邏輯調用逾時,進入步驟8.

  6. 判斷邏輯是否調用成功

    a: 傳回成功調用結果

    b: 調用出錯,進入步驟8.

  7. 計算熔斷器狀态,所有的運作狀态(成功, 失敗, 拒絕,逾時)上報給熔斷器,用于統計進而判斷熔斷器狀态.
  8. getFallback()降級邏輯.以下四種情況将觸發getFallback調用:(1):run()方法抛出非HystrixBadRequestException異常;(2):run()方法調用逾時;(3):熔斷器開啟攔截調用;(4):線程池/隊列/信号量是否跑滿。

    a: 沒有實作getFallback的Command将直接抛出異常

    b: fallback降級邏輯調用成功直接傳回

    c: 降級邏輯調用失敗抛出異常

  9. 傳回執行成功結果

Hystrix測試說明

高并發之——服務降級與熔斷

Hystrix特性

  1. 請求熔斷: 當Hystrix Command請求後端服務失敗數量超過一定比例(預設50%), 斷路器會切換到開路狀态(Open). 這時所有請求會直接失敗而不會發送到後端服務. 斷路器保持在開路狀态一段時間後(預設5秒), 自動切換到半開路狀态(HALF-OPEN).

這時會判斷下一次請求的傳回情況, 如果請求成功, 斷路器切回閉路狀态(CLOSED), 否則重新切換到開路狀态(OPEN). Hystrix的斷路器就像我們家庭電路中的保險絲, 一旦後端服務不可用, 斷路器會直接切斷請求鍊, 避免發送大量無效請求影響系統吞吐量, 并且斷路器有自我檢測并恢複的能力.

  2. 服務降級:Fallback相當于是降級操作. 對于查詢操作, 我們可以實作一個fallback方法, 當請求後端服務出現異常的時候, 可以使用fallback方法傳回的值. fallback方法的傳回值一般是設定的預設值或者來自緩存.告知後面的請求服務不可用了,不要再來了。

  3. 依賴隔離(采用艙壁模式,Docker就是艙壁模式的一種):在Hystrix中, 主要通過線程池來實作資源隔離. 通常在使用的時候我們會根據調用的遠端服務劃分出多個線程池.比如說,一個服務調用兩外兩個服務,你如果調用兩個服務都用一個線程池,那麼如果一個服務卡在哪裡,資源沒被釋放

後面的請求又來了,導緻後面的請求都卡在哪裡等待,導緻你依賴的A服務把你卡在哪裡,耗盡了資源,也導緻了你另外一個B服務也不可用了。這時如果依賴隔離,某一個服務調用A B兩個服務,如果這時我有100個線程可用,我給A服務配置設定50個,給B服務配置設定50個,這樣就算A服務挂了,我的B服務依然可以用。

  4. 請求緩存:比如一個請求過來請求我userId=1的資料,你後面的請求也過來請求同樣的資料,這時我不會繼續走原來的那條請求鍊路了,而是把第一次請求緩存過了,把第一次的請求結果傳回給後面的請求。

  5. 請求合并:我依賴于某一個服務,我要調用N次,比如說查資料庫的時候,我發了N條請求發了N條SQL然後拿到一堆結果,這時候我們可以把多個請求合并成一個請求,發送一個查詢多條資料的SQL的請求,這樣我們隻需查詢一次資料庫,提升了效率。

​​參考文章​​

Hystrix如何解決依賴隔離

  1. Hystrix使用指令模式HystrixCommand(Command)包裝依賴調用邏輯,每個指令在單獨線程中/信号授權下執行。
  2. 可配置依賴調用逾時時間,逾時時間一般設為比99.5%平均時間略高即可.當調用逾時時,直接傳回或執行fallback邏輯。
  3. 為每個依賴提供一個小的線程池(或信号),如果線程池已滿調用将被立即拒絕,預設不采用排隊.加速失敗判定時間。
  4. 依賴調用結果分:成功,失敗(抛出異常),逾時,線程拒絕,短路。 請求失敗(異常,拒絕,逾時,短路)時執行fallback(降級)邏輯。
  5. 提供熔斷器元件,可以自動運作或手動調用,停止目前依賴一段時間(10秒),熔斷器預設錯誤率門檻值為50%,超過将自動運作。
  6. 提供近實時依賴的統計和監控

​​推薦文章​​

服務熔斷

服務熔斷也被稱為服務過載保護。

如下圖所示:

高并發之——服務降級與熔斷

其實可以認為:服務熔斷是服務降級的措施。

服務熔斷與服務降級比較

  1. 服務熔斷對服務提供了proxy,防止服務不可能時,出現串聯故障(cascading failure),導緻雪崩效應。
  2. 服務熔斷一般是某個服務(下遊服務)故障引起,而服務降級一般是從整體負荷考慮。
  3. 共性:
  • 目的 -> 都是從可用性、可靠性出發,提高系統的容錯能力。
  • 最終表現->使某一些應用不可達或不可用,來保證整體系統穩定。
  • 粒度 -> 一般都是服務級别,但也有細粒度的層面:如做到資料持久層、隻許查詢不許增删改等。
  • 自治 -> 對其自治性要求很高。都要求具有較高的自動處理機制。
  1. 差別:
  • 觸發原因 -> 服務熔斷通常是下級服務故障引起;服務降級通常為整體系統而考慮。
  • 管理目标 -> 熔斷是每個微服務都需要的,是一個架構級的處理;而服務降級一般是關注業務,對業務進行考慮,抓住業務的層級,進而決定在哪一層上進行處理:比如在IO層,業務邏輯層,還是在外圍進行處理。
  • 實作方式 -> 代碼實作中的差異。

服務熔斷中需考慮的設計:

源自部落客張善友的觀點:

  1. 異常處理:調用受熔斷器保護的服務的時候,我們必須要處理當服務不可用時的異常情況。這些異常處理通常需要視具體的業務情況而定。比如,如果應用程式隻是暫時的功能降級,可能需要切換到其它的可替換的服務上來執行相同的任務或者擷取相同的資料,或者給使用者報告錯誤然後提示他們稍後重試。
  2. 異常的類型:請求失敗的原因可能有很多種。一些原因可能會比其它原因更嚴重。比如,請求會失敗可能是由于遠端的服務崩潰,這可能需要花費數分鐘來恢複;也可能是由于伺服器暫時負載過重導緻逾時。熔斷器應該能夠檢查錯誤的類型,進而根據具體的錯誤情況來調整政策。比如,可能需要很多次逾時異常才可以斷定需要切換到斷開狀态,而隻需要幾次錯誤提示就可以判斷服務不可用而快速切換到斷開狀态。
  3. 日志:熔斷器應該能夠記錄所有失敗的請求,以及一些可能會嘗試成功的請求,使得的管理者能夠監控使用熔斷器保護的服務的執行情況。
  4. 測試服務是否可用:在斷開狀态下,熔斷器可以采用定期的ping遠端的服務或者資源,來判斷是否服務是否恢複,而不是使用計時器來自動切換到半斷開狀态。這種ping操作可以模拟之前那些失敗的請求,或者可以使用通過調用遠端服務提供的檢查服務是否可用的方法來判斷。
  5. 手動重置:在系統中對于失敗操作的恢複時間是很難确定的,提供一個手動重置功能能夠使得管理者可以手動的強制将熔斷器切換到閉合狀态。同樣的,如果受熔斷器保護的服務暫時不可用的話,管理者能夠強制的将熔斷器設定為斷開狀态。
  6. 并發問題:相同的熔斷器有可能被大量并發請求同時通路。熔斷器的實作不應該阻塞并發的請求或者增加每次請求調用的負擔。
  7. 資源的差異性:使用單個熔斷器時,一個資源如果​​有分布在多個地方就需要小心。比如,一個資料可能存儲在多個磁盤分區上(shard),某個分區可以正常通路,而另一個可能存在暫時性的問題。在這種情況下,不同的錯誤響應如果混為一談,那麼應用程式通路的這些存在問題的分區的失敗的可能性就會高,而那些被認為是正常的分區,就有可能被阻塞。
  8. 加快熔斷器的熔斷操作:有時候,服務傳回的錯誤資訊足夠讓熔斷器立即執行熔斷操作并且保持一段時間。比如,如果從一個分布式資源傳回的響應提示負載超重,那麼應該等待幾分鐘後再重試。(HTTP協定定義了”HTTP 503 Service Unavailable”來表示請求的服務目前不可用,他可以包含其他資訊比如,逾時等)
  9. 重複失敗請求:當熔斷器在斷開狀态的時候,熔斷器可以記錄每一次請求的細節,而不是僅僅傳回失敗資訊,這樣當遠端服務恢複的時候,可以将這些失敗的請求再重新請求一次。

服務熔斷恢複需注意的問題