Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)

作積極的人,越努力越幸運!
Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
本文是源碼分析 Sentinel 系列的第十三篇,已經很是詳細的介紹了 Sentinel 的架構體系、滑動窗口、調用鏈上下文、限流、熔斷的實現原理,相信各位讀者朋友們對Sentinel有一個較爲體系化的認知了,這個時候是該開始如何在生產環境進行運用了。java

本文將以 Dubbo 服務調用爲案例剖析場景,嘗試對官方提供的 Dubbo 適配器作一個研究學習並對此作出本身的評價,拋出個人觀點,期待與你們共同探討,交流。redis

一個 Dubbo RPC 的簡易調用過程以下圖所示:
Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)算法

消費者會維護一個服務提供者列表,而後再發一塊兒一個服務調用的時候會首先根據負載均衡算法從中選擇一個服務提供者,而後發起 RPC 調用,在請求真實發送以前會依次經過客戶端設置的過濾器鏈(Filter),而後通過網絡傳輸到到達服務提供者,並執行完服務提供者端的 Filter,最後進入到業務邏輯執行並返回結果。網絡

Sentinel 與 Dubbo 的整合就是利用了 Dubbo 的 Filter 機制,爲 Dubbo 提供對應的 過濾器,無縫實現限流、熔斷等功能,作到業務無感知,即業務代碼無需使用 Sentinel 相關的 API。
接下來請你們帶着在 Dubbo 中如何使用限流、熔斷方面來看官方給出的解決方案。架構

思考題:在看接下來的內容以前,建議你們稍做停頓,思考一下,在服務調用模型中,限流、熔斷一般在哪一個端作比較合適。負載均衡

一、從消費端來看限流與熔斷


Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
從消費端的視角,雖然提供了服務端的負載均衡,但從客戶端不論是向192.168.1.3仍是向192.168.1.4發送RPC調用,都會通過同一個 Sentinel Dubbo Filter。這個看似簡單明瞭,但這是咱們接下來思考的最基本最核心的點。
咱們先來看看官方提供的 Dubbo 適配器的核心實現:ide

Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
SentinelDubboConsumerFilter#invoke
消費端這邊使用到了兩個資源名稱,一個是接口級別,例如 com.demo.service.UserService,另一是方法級別,例如 com.demo.servcie.UserServce#findUser(Ljava.lang.String)。
定義了兩個資源後,Sentinel 會使用滑動窗口機制,爲上述兩個資源收集實時的調用信息,爲後續的限流、熔斷提供數據依據。
限流規則是依附於具體某一個項目的,例如以下圖所示:源碼分析

Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
限流、熔斷都是根據資源級別,若是須要對消費端的調用進行限流的話,就須要爲這兩個資源配置對應的限流規則,若是不配置則默認經過,表示不限流。學習

1.1 服務調用端(消費方)是否須要配置限流規則

在 dubbo 的服務調用場景中,在消費端設置限流的規則的話,這個調用鏈是針對整個集羣全部服務提供者的,例如當前集羣中包含3個服務提供者,每一個服務提供者用於1000tps的服務能力,那消費端的限流,應該配置的限流TPS應該爲3000tps,若是設置爲1000tps,則沒法完整的利用服務端的能力,基於這樣的狀況,一般消費端無需配置限流規則。架構設計

那是否是說消費端就不必配置限流規則呢?其實也不是,有以下這個場景,例如調用第三方外部的計費類服務接口,對方一般爲特定的帳戶等級設置對應的TPS上限,若是超過該調用頻率就會拋出錯誤,這種狀況仍是須要設置限流規則,確保消費端以不超過要求進行調用,避免業務異常。

1.2 服務調用端(消費方)是否須要配置熔斷

引入熔斷的目的是避免服務端單節點響應慢而致使這個服務不穩定,例如示例中有3個服務提供者,若是192.168.1.3的服務提供者因爲觸發了BUG致使響應時間大大增長,致使發往該服務提供者的請求大機率超時,在這樣的狀況下但願在接下來某段時間內消費方發往這這個服務提供者的請求快速熔斷降級,返回錯誤,由客戶端重試其餘服務提供者。其實現效果以下:
Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
當前的 Sentinel 默認是否能知足上述的需求呢?
咱們以 Sentinel 基於異常比例熔斷策略來進行闡述,若是資源的調用異常比例超過必定值是會觸發降級熔斷,拋出 DegradeException 異常。

因爲總共只有三個服務提供者,其中發往192.168.1.3的請求大機率會因爲超時失敗,則異常比例會超過設置的熔斷降級規則,會觸發降級,形成的效果是整個服務調用都會發送熔斷降級,即調用192.168.1.4,5兩個請求都不會被熔斷,形成整個服務調用不可用,與指望不一致。即仍是會出現一個節點的不穩定而致使整個服務不穩定的狀況。

其形成的根本緣由是由於其資源的定義並無包含服務提供者的信息,改進的初步方案:

  1. 在過濾器中再定義一個資源,加上服務提供的IP與端口號,例如 SphU.entry("com.d.s.UserService@ip:port"),對單個服務提供者進行單獨收集調用信息,而且須要提供一可配置的項,用來標記該類型的資源在作熔斷判斷可以使用某一個資源的配置,例如配置爲 com.d.s.UserService,表示用這個配置規則來判斷熔斷。
  2. 在熔斷規則判斷的時候,該資源使用被引用資源的熔斷規則進行判斷。
    最後來解答一下,熔斷規則一般只須要配置在調用方便可。

二、從服務端來看限流與熔斷


因爲服務端看限流與熔斷就比較簡單,由於服務端與客戶端存在一個很是大的區別是客戶端存在負載均衡機制,一個消費端對於同一資源來講,會調用多個服務提供者,而服務提供者對於一個資源來就是其自身,故限流規則,熔斷規則都是針對個體,其複雜度下降。

爲了知識體系的完備性,咱們來看一下 Sentinel Dubbo 在服務端的適配器的實現。

Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
SentinelDubboProviderFilter#invoke

這裏有二個關鍵點:

  1. 使用了 ContextUtil 的 entry 方法,定義本次調用的上下文環境名稱爲:resourceName,默認爲接口名與方法名、參數列表,例如 com.d.s.UserServce#findUser(Ljava.lang.String),源頭爲消費端的應用名稱。
  2. 定義兩個資源,這裏與消費端相同,就不作重複解讀。
    關於這個 ContextUtil 的 entry 方法很是關鍵,由於 Sentinel 中數據節點的統計是以 ContextName 爲維度的。

例如想對一個應用全部的操做 redis 操做統一設置爲一個資源名,redisOpsResource,即想控制該應用總體的 redis 操做 tps,其場景以下:

Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)
例如初衷設計爲 opsReisTotal 的整個 tps 爲 500,例如從UserService#findser鏈路的訪問 redis tps 爲 400,而從 Order#createOrder 鏈路訪問 redis tps 爲 400,此時 redis 的總體 tps 已經達到了 800 tps,但你會發現並不會觸發限流,由於對資源 RredisOpResource 的調用信息統計是以 context name 爲維度的,不一樣的 context name 互不影響,從而沒法作到全局控制。

三、總結


本文結合 Sentinel 官方對於 Dubbo 提供的適配器並加以理解,提出了以下觀點,歡迎你們留言探討,相互交流,共同進步。

  1. 限流規則根據不一樣的使用場景能夠在客戶端、服務端配置。
  2. 熔斷規則一般在服務調用方配置便可。
  3. Sentinel 目前的熔斷還實現的比較簡單,沒法解決集羣中由於某一個節點的訪問慢而觸發熔斷,並使服務穩定的能力。
  4. Sentienl 的實時統計是以調用上下文(Context Name),即 ContextUtil.entry 方法定義的上下文爲維度的,這點很是關鍵,否則容易踩坑。

歡迎加入個人知識星球,一塊兒交流源碼,探討架構,揭祕億級訂單的架構設計與實踐經驗,打造高質量的技術交流圈,爲廣大星友提供高質量問答服務,長按以下二維碼加入。
Sentinel Dubbo 適配器看限流與熔斷(實戰思考篇)

相關文章
相關標籤/搜索