1. 程式人生 > 實用技巧 >1.1 Sentinel介紹

1.1 Sentinel介紹

目錄

Pt1 基本概念

Pt2 主要特性

Pt3 核心原理

Pt3.1 Sentinel框架

Pt3.2 常用Slot

NodeSelectorSlot

ClusterBuilderSlot

StatisticSlot

FlowSlot

DegradeSlot

SystemSlot

Pt3.3 核心類

ProcessorSlotChain

Context

Entry

Node

StatisticSlot


隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分散式服務架構的流量控制組件,主要以流量為切入點,從限流、流量整形、熔斷降級、系統負載保護、熱點防護等多個維度來幫助開發者保障微服務的穩定性。

Pt1 基本概念

  • 限流

    限流是從系統能夠承受的請求量考慮,應對突發流量的是系統保護策略。當請求的流量異常(突發流量或者是流量過載)時,為了進行自我保護,超過的流量將直接被丟棄或者進行排隊處理(導致平均響應時間RT增高)。

  • 熔斷

    熔斷是從外部服務故障考慮,應對外部故障時的系統保護策略。主要有兩種場景:上游系統請求量異常,對上游請求流量進行熔斷,防止系統被壓垮;下游依賴成功率或處理時間異常,對下游進行熔斷,防止因下游導致自身處理變慢而導致的流量異常被壓垮。

  • 降級

    當自身服務發生故障時,可以關閉當前服務,約定一個快速失敗的Fallback,防止對上游呼叫鏈造成更大的影響。比如:連線超時、網路延遲、伺服器響應時間過長。

  • 限流 Vs 熔斷 Vs 降級 區別

    限流主要出於對異常流量考慮,為了保證系統不被突發流量擊垮。

    熔斷是出於服務故障考慮,應對服務中不穩定因素,防止遠端服務故障引發的資源阻塞導致自身服務風險。

    降級通常是和熔斷一起使用,犧牲非核心功能,或者對故障服務執行快速失敗處理,防止引發雪崩效應。

  • 資源(需要被保護的)

    資源是 Sentinel 的關鍵概念。它可以是 Java 應用程式中的任何內容,例如,由應用程式提供的服務,或由應用程式呼叫的其它應用提供的服務,甚至可以是一段程式碼。只要通過 Sentinel API 定義的程式碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來標示資源。

  • 規則(限流規則/熔斷規則)

    圍繞資源的實時狀態設定的規則,可以包括流量控制規則、熔斷降級規則以及系統保護規則。所有規則可以動態實時調整。

Pt2 主要特性

Sentinel 分為兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 執行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支援。

  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接執行,不需要額外的 Tomcat 等應用容器。

Pt3 核心原理

Sentinel 的主要工作機制如下:

  • 對主流框架提供適配或者顯示的 API,來定義需要保護的資源,並提供設施對資源進行實時統計和呼叫鏈路分析。

  • 根據預設的規則,結合對資源的實時統計資訊,對流量進行控制。同時,Sentinel 提供開放的介面,方便您定義及改變規則。

  • Sentinel 提供實時的監控系統,方便您快速瞭解目前系統的狀態。

Pt3.1 Sentinel框架

在 Sentinel 裡面,所有的資源都對應一個資源名稱(resourceName),每次資源呼叫都會建立一個 Entry 物件。Entry 可以通過對主流框架的適配自動建立,也可以通過註解的方式或呼叫 SphU API 顯式建立。Entry 建立的時候,同時也會建立一系列功能插槽(slot chain),這些插槽有不同的職責,例如:

  • NodeSelectorSlot 負責收集資源的路徑,並將這些資源的呼叫路徑,以樹狀結構儲存起來,用於根據呼叫路徑來限流降級;

  • ClusterBuilderSlot 則用於儲存資源的統計資訊以及呼叫者資訊,例如該資源的 RT, QPS, thread count 等等,這些資訊將用作為多維度限流,降級的依據;

  • StatisticSlot 則用於記錄、統計不同緯度的 runtime 指標監控資訊;

  • FlowSlot 則用於根據預設的限流規則以及前面 slot 統計的狀態,來進行流量控制;

  • AuthoritySlot 則根據配置的黑白名單和呼叫來源資訊,來做黑白名單控制;

  • DegradeSlot 則通過統計資訊以及預設的規則,來做熔斷降級;

  • SystemSlot 則通過系統的狀態,例如 load1 等,來控制總的入口流量;

總體的框架如下:

Sentinel 將 ProcessorSlot 作為 SPI 介面進行擴充套件(1.7.2 版本以前 SlotChainBuilder 作為 SPI),使得 Slot Chain 具備了擴充套件的能力。您可以自行加入自定義的 slot 並編排 slot 間的順序,從而可以給 Sentinel 新增自定義的功能。

Pt3.2 常用Slot

NodeSelectorSlot

這個 slot 主要負責收集資源的路徑,並將這些資源的呼叫路徑以樹狀結構儲存起來,用於根據呼叫路徑進行流量控制。

 ContextUtil.enter("entrance1", "appA");
 Entry nodeA = SphU.entry("nodeA");
 if (nodeA != null) {
   nodeA.exit();
 }
 ContextUtil.exit();

上述程式碼通過 ContextUtil.enter() 建立了一個名為 entrance1 的上下文,同時指定呼叫發起者為 appA;接著通過SphU.entry()請求一個 token,如果該方法順利執行沒有拋 BlockException,表明 token 請求成功。

以上程式碼將在記憶體中生成以下結構:

       machine-root
         /   
         /
     EntranceNode1
        /
       /  
    DefaultNode(nodeA)

注意:每個 DefaultNode 由資源 ID 和輸入名稱來標識。換句話說,一個資源 ID 可以有多個不同入口的 DefaultNode。

  ContextUtil.enter("entrance1", "appA");
  Entry nodeA = SphU.entry("nodeA");
  if (nodeA != null) {
   nodeA.exit();
  }
  ContextUtil.exit();
​
  ContextUtil.enter("entrance2", "appA");
  nodeA = SphU.entry("nodeA");
  if (nodeA != null) {
   nodeA.exit();
  }
  ContextUtil.exit();

以上程式碼將在記憶體中生成以下結構:

          machine-root
          /     \
          /      \
      EntranceNode1  EntranceNode2
         /        \
        /         \
    DefaultNode(nodeA)  DefaultNode(nodeA)

上面的結構可以通過呼叫 curl http://localhost:8719/tree?type=root 來顯示:

EntranceNode: machine-root(t:0 pq:1 bq:0 tq:1 rt:0 prq:1 1mp:0 1mb:0 1mt:0)
-EntranceNode1: Entrance1(t:0 pq:1 bq:0 tq:1 rt:0 prq:1 1mp:0 1mb:0 1mt:0)
--nodeA(t:0 pq:1 bq:0 tq:1 rt:0 prq:1 1mp:0 1mb:0 1mt:0)
-EntranceNode2: Entrance1(t:0 pq:1 bq:0 tq:1 rt:0 prq:1 1mp:0 1mb:0 1mt:0)
--nodeA(t:0 pq:1 bq:0 tq:1 rt:0 prq:1 1mp:0 1mb:0 1mt:0)
​
t:threadNum  pq:passQps  bq:blockedQps  tq:totalQps  rt:averageRt  prq: passRequestQps 1mp:1m-passed 1mb:1m-blocked 1mt:1m-total

ClusterBuilderSlot

此插槽用於構建資源的 ClusterNode 以及呼叫來源節點。ClusterNode 保持某個資源執行統計資訊(響應時間、QPS、block 數目、執行緒數、異常數等)以及呼叫來源統計資訊列表。呼叫來源的名稱由 ContextUtil.enter(contextName,origin) 中的 origin 標記。可通過如下命令檢視某個資源不同調用者的訪問情況:curl http://localhost:8719/origin?id=caller

id: nodeA
idx origin  threadNum passedQps blockedQps totalQps aRt  1m-passed 1m-blocked 1m-total 
1  caller1 0     0     0      0     0   0     0      0    
2  caller2 0     0     0      0     0   0     0      0    

StatisticSlot

StatisticSlot 是 Sentinel 的核心功能插槽之一,用於統計實時的呼叫資料。

  • clusterNode:資源唯一標識的 ClusterNode 的實時統計

  • origin:根據來自不同調用者的統計資訊

  • defaultnode: 根據入口上下文區分的資源 ID 的 runtime 統計

  • 入口流量的統計

Sentinel 底層採用高效能的滑動視窗資料結構 LeapArray 來統計實時的秒級指標資料,可以很好地支撐寫多於讀的高併發場景。

FlowSlot

這個 slot 主要根據預設的資源的統計資訊,按照固定的次序,依次生效。如果一個資源對應兩條或者多條流控規則,則會根據如下次序依次檢驗,直到全部通過或者有一個規則生效為止:

  • 指定應用生效的規則,即針對呼叫方限流的;

  • 呼叫方為 other 的規則;

  • 呼叫方為 default 的規則。

DegradeSlot

這個 slot 主要針對資源的平均響應時間(RT)以及異常比率,來決定資源是否在接下來的時間被自動熔斷掉。

SystemSlot

這個 slot 會根據對於當前系統的整體情況,對入口資源的呼叫進行動態調配。其原理是讓入口的流量和當前系統的預計容量達到一個動態平衡。

注意系統規則只對入口流量起作用(呼叫型別為 EntryType.IN),對出口流量無效。可通過 SphU.entry(res, entryType) 指定呼叫型別,如果不指定,預設是EntryType.OUT

Pt3.3 核心類

ProcessorSlotChain

Sentinel 的核心骨架,將不同的 Slot 按照順序串在一起(責任鏈模式),從而將不同的功能(限流、降級、系統保護)組合在一起。slot chain 其實可以分為兩部分:統計資料構建部分(statistic)和判斷部分(rule checking)。

核心結構:

目前的設計是 one slot chain per resource,因為某些 slot 是 per resource 的(比如 NodeSelectorSlot)。

Context

Context 代表呼叫鏈路上下文,貫穿一次呼叫鏈路中的所有 Entry。Context 維持著入口節點(entranceNode)、本次呼叫鏈路的 curNode、呼叫來源(origin)等資訊。Context 名稱即為呼叫鏈路入口名稱。

Context 維持的方式:通過 ThreadLocal 傳遞,只有在入口 enter 的時候生效。由於 Context 是通過 ThreadLocal 傳遞的,因此對於非同步呼叫鏈路,執行緒切換的時候會丟掉 Context,因此需要手動通過 ContextUtil.runOnContext(context, f) 來變換 context。

Entry

每一次資源呼叫都會建立一個 EntryEntry 包含了資源名、curNode(當前統計節點)、originNode(來源統計節點)等資訊。

CtEntry 為普通的 Entry,在呼叫 SphU.entry(xxx) 的時候建立。特性:Linked entry within current context(內部維護著 parentchild

需要注意的一點:CtEntry 建構函式中會做呼叫鏈的變換,即將當前 Entry 接到傳入 Context 的呼叫鏈路上(setUpEntryFor)。

資源呼叫結束時需要 entry.exit()。exit 操作會過一遍 slot chain exit,恢復呼叫棧,exit context 然後清空 entry 中的 context 防止重複呼叫。

Node

Sentinel 裡面的各種種類的統計節點:

  • StatisticNode:最為基礎的統計節點,包含秒級和分鐘級兩個滑動視窗結構。

  • DefaultNode:鏈路節點,用於統計呼叫鏈路上某個資源的資料,維持樹狀結構。

  • ClusterNode:簇點,用於統計每個資源全域性的資料(不區分呼叫鏈路),以及存放該資源的按來源區分的呼叫資料(型別為 StatisticNode)。特別地,Constants.ENTRY_NODE 節點用於統計全域性的入口資源資料。

  • EntranceNode:入口節點,特殊的鏈路節點,對應某個 Context 入口的所有呼叫資料。Constants.ROOT 節點也是入口節點。

構建的時機:

  • EntranceNodeContextUtil.enter(xxx) 的時候就建立了,然後塞到 Context 裡面。

  • NodeSelectorSlot:根據 context 建立 DefaultNode,然後 set curNode to context。

  • ClusterBuilderSlot:首先根據 resourceName 建立 ClusterNode,並且 set clusterNode to defaultNode;然後再根據 origin 建立來源節點(型別為 StatisticNode),並且 set originNode to curEntry。

幾種 Node 的維度(數目):

  • ClusterNode 的維度是 resource

  • DefaultNode 的維度是 resource * context,存在每個 NodeSelectorSlot 的 map 裡面

  • EntranceNode 的維度是 context,存在 ContextUtil 類的 contextNameNodeMap 裡面

  • 來源節點(型別為 StatisticNode)的維度是 resource * origin,存在每個 ClusterNode 的 originCountMap 裡面

StatisticSlot

StatisticSlot 是 Sentinel 最為重要的類之一,用於根據規則判斷結果進行相應的統計操作。

entry 的時候:依次執行後面的判斷 slot。每個 slot 觸發流控的話會丟擲異常(BlockException 的子類)。若有 BlockException 丟擲,則記錄 block 資料;若無異常丟擲則算作可通過(pass),記錄 pass 資料。

exit 的時候:若無 error(無論是業務異常還是流控異常),記錄 complete(success)以及 RT,執行緒數-1。

記錄資料的維度:執行緒數+1、記錄當前 DefaultNode 資料、記錄對應的 originNode 資料(若存在 origin)、累計 IN 統計資料(若流量型別為 IN)。