Sentinel 原理-如何為系統設定擴充套件點

逅弈逐碼發表於2019-02-01

Sentinel 系列教程,現已上傳到 github 和 gitee 中,並會長期更新 Sentinel 中的知識點和實踐經驗,我希望用更簡單的demo和更易懂的圖文描述慢慢揭開 Sentinel 的面紗,歡迎大家加入一起學習,為 Sentinel 的發展做出一點貢獻:

  • GitHub:

  • Gitee:

    4you/sentinel-tutorial

Sentinel 原理-如何為系統設定擴充套件點

一個好的框架有一個很重要的特性就是擴充套件性要好,不能把系統寫死,後期想要新增功能時,可以透過預留的擴充套件點進行擴充套件,而不是去修改原來的程式碼。

本篇文章我就來跟大家分享下 Sentinel 在擴充套件性這塊是怎麼做的,都有哪些擴充套件點。

模組設計

第一點從模組設計上,Sentinel 就充分考慮了擴充套件性,Sentinel 核心的功能其實就在 sentinel-core 模組中,要想在自己的系統中使用 Sentinel 最少只需要引入這一個依賴就夠了。其他的都是為了框架的易用性和高可用性等做的擴充套件。

我們來看下 Sentinel 中都有哪些擴充套件的模組:

  • sentinel-dashboard:一個透過 spring boot 實現的 web 應用,相當於是 Sentinel 的 OPS 工具,透過 dashboard 我們可以更方便的對規則進行調整、查詢實時統計資訊等,但是這並不是必須的,沒有 dashboard 我們也能使用 Sentinel,甚至我們可以透過 Sentinel 提供的 api 來實現自己的 dashboard。

  • sentinel-transport:一個 sentinel-core 和 sentinel-dashboard 通訊的橋樑,如果我們的應用接入了 Sentinel,並且也想透過 dashboard 來管理的話,那就需要引入 sentinel-transport 模組。

  • sentinel-extension:一個 Sentinel 的擴充套件模組,主要是實現了規則的動態更新和持久化。另外熱點引數限流也在這裡實現的,除此之外註解的相關實現也是在這個模組中。

  • sentinel-adapter:一個介面卡的擴充套件,透過介面卡可以很方便的為其他框架進行 Sentinel 的整合。

  • sentinel-cluster:叢集限流的擴充套件,透過引入這個模組可以在叢集環境中使用 Sentinel。

除了 sentinel-core 之外,其他的模組基本上都是圍繞著 sentinel-core 做了一些擴充套件,而且各個模組之間沒有強耦合,是可插拔的,以下這張圖可以簡單的描述這個關係:

Sentinel 原理-如何為系統設定擴充套件點

系統初始化

Sentinel 為我們提供了一個 InitFunc 介面來做系統的初始化工作,如果我們想要實現在系統初始化時就執行的邏輯,可以實現 InitFunc 介面。

目前 Sentinel 中有一些實現了 InitFunc 的類:

Sentinel 原理-如何為系統設定擴充套件點

主要實現了以下這些系統初始化的工作:

  • CommandCenter 的初始化

  • HeartBeat 的初始化與心跳傳送

  • 叢集服務端和客戶端的初始化

  • 熱點限流中 StatisticSlot 回撥的初始化

並且我們我們可以透過 @InitOrder 註解來指定 InitFunc 執行的順序,order 的值越小越先執行。

InitFunc 是在首次呼叫 SphU.entry(KEY) 方法時觸發的,註冊的初始化函式會依次執行。

如果你不想把初始化的工作延後到第一次呼叫時觸發,可以手動呼叫 InitExecutor.doInit() 函式,重複呼叫只會執行一次。

規則持久化

限流降級的規則,是透過呼叫 loadRules 方法載入進記憶體中的,而實際使用中,我們必須要對規則進行持久化,因為不進行持久化的話規則將會在系統重啟時丟失。

那麼 Sentinel 是如何做到,在擴充套件了動態規則載入的方法時,又不影響原先正常的規則載入的呢?我們看一下 FlowRuleManager 的 loadRules 方式就知道了:

private static SentinelProperty<List<FlowRule>> currentProperty = new DynamicSentinelProperty<List<FlowRule>>();/** * Load {@link FlowRule}s, former rules will be replaced. * * @param rules new rules to load. */public static void loadRules(List<FlowRule> rules) {    currentProperty.updateValue(rules);}

實際上是透過 DynamicSentinelProperty 的 updateValue 方法來動態更新規則的。

那麼我們只需要在持久化的規則發生變更時,透過觸發 SentinelProperty 的 updateValue 方法把更新後的規則注入進去就可以了。目前 SentinelProperty 有預設的實現,這一塊我們不需要進行擴充套件,我們只需要實現監聽每種持久化的資料來源在發生資料變更時的事件,當接收到最新的資料時將它 update 進 FlowRuleManager 中即可。

所以我們需要抽象出讀資料來源和寫資料來源的兩個介面:

  • ReadableDataSource:讀資料來源負責監聽持久化的資料來源的變更,在接收到變更事件時將最新的資料更新

  • WritableDataSource:寫資料來源負責將變更後的規則寫入到持久化的資料來源中

目前系統中只有一種檔案資料來源實現了 WritableDataSource 介面,其他的資料來源只實現了 ReadableDataSource 介面。

Sentinel 原理-如何為系統設定擴充套件點

網路通訊

sentinel-transport 模組中的功能基本上都是網路通訊相關的,而我們有很多的網路協議:http、tcp等,所以網路通訊這塊肯定也要有可擴充套件的能力。目前 sentinel-transport-common 模組中抽象了3個介面作為擴充套件點:

  • CommandCenter:該介面主要用來在 sentinel-core 中啟動一個可以對外提供 api 介面的服務端,Sentinel 中預設有兩個實現,分別是 http 和 netty。但是官方預設推薦的是使用 http 的實現。

  • CommandHandler:該介面主要是用來處理接收到的請求的,不同的請求有不同的 handler 類來進行處理,我們可以實現我們自己的 CommandHandler 並註冊到 SPI 配置檔案中來為 CommandCenter 新增自定義的命令。

  • HeartbeatSender:該介面主要是為 sentinel-core 用來向 sentinel-dashboard 傳送心跳的,預設也有兩個實現,分別是 http 和 netty。

Sentinel 原理-如何為系統設定擴充套件點

Slot鏈

Sentinel 內部是透過一系列的 slot 組成的 slot chain 來完成各種功能的,包括構建呼叫鏈、呼叫資料統計、規則檢查等,各個 slot 之間的順序非常重要。

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

Sentinel 原理-如何為系統設定擴充套件點

StatisticSlot回撥

之前 StatisticSlot 裡面包含了太多的邏輯,像普通 qps 和 熱點引數 qps 的 addPass/addBlock 等邏輯統計都在 StatisticSlot 裡面,各個邏輯都雜糅在一起,不利於擴充套件。

因此有必要為 StatisticSlot 抽象出一系列的 callback,從而使 StatisticSlot 具備基本的擴充套件能力,並將一系列的邏輯從 StatisticSlot 解耦出來,目前 Sentinel 提供了兩種 callback:


  • ProcessorSlotEntryCallback

    包含 onPass 和 onBlocked 兩個回撥函式,分別對應著請求在 pass 和 blocked 的時候執行。


  • ProcessorSlotExitCallback

    包含 onExit 回撥函式,對應著請求在 exit 的時候執行。

只需將實現的 callback 註冊到 StatisticSlotCallbackRegistry 即可生效。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69908605/viewspace-2565384/,如需轉載,請註明出處,否則將追究法律責任。

相關文章