Sentinel使用指南

Sentinel 簡介

Sentinel 是阿里中間件團隊開源的一款面向分佈式服務架構的輕量級高可用的流量控制組件。

As distributed systems become increasingly popular, the reliability between services is becoming more important than ever before. Sentinel takes “flow” as breakthrough point, and works on multiple fields including flow control, circuit breaking and system adaptive protection, to guarantee reliability of microservices.
隨着分佈式系統的日益普及,服務間的可靠性變得越來越重要。哨兵以“流量”爲突破口,在流量控制、斷路、系統自適應保護等多個領域開展工作,保證微服務的可靠性
(引用自官方文檔)

Sentinel具有的特徵

  • 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峯填谷、集羣流量控制、實時熔斷下游不可用應用等。
  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集羣的彙總運行情況。
  • 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
  • 完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定製邏輯。例如定製規則管理、適配動態數據源等。

在這裏插入圖片描述

Sentinel的組成

Sentinel 分爲兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。

相關術語

  • Resource
    在Sentinel中,Resource是資源的意思,它可以是代碼塊、方法、接口等任何需要保護的東西。在編程的時候,如果這個代碼是否需要保護,那麼我們就將之定義爲一個資源
  • Slot
    Slot是指Sentinel中的插槽。Sentinel的工作流程是圍繞着一個個插槽所組成的插槽鏈來展開的。每個Slot都有自己的功能,通過一定的編排順序,來達到最終的限流降級的目的。默認的各個插槽之間的順序是固定的,因爲有的插槽需要依賴其他的插槽計算出來的結果才能進行工作。
  • Context
    Context是指調用鏈路上下文,它貫穿一次調用鏈路中的所有 Entry。Context 維護着當前調用鏈的元數據:入口節點、本次調用鏈路節點、調用來源等信息,通過 ThreadLocal 傳遞。
  • Entry
    Entry是指Sentinel中請求是否通過限流的一個憑證。每次執行 SphU.entry() 或 SphO.entry() 都會返回一個 Entry 給調用者。資源調用結束時需要 entry.exit()。Entry 包含了資源名、curNode(當前統計節點)、originNode(來源統計節點)等信息。
  • Node
    節點。在Sentinel中保存統計數據的對象有4種:
  1. StatisticNode:統計節點,最爲基礎的統計節點,包含秒級和分鐘級兩個滑動窗口結構。
  2. DefaultNode:鏈路節點,用於統計調用鏈路上某個資源的數據,維持樹狀結構。
  3. ClusterNode:簇節點,用於統計每個資源全局的數據(不區分調用鏈路),以及存放該資源的按來源區分的調用數據。
  4. EntranceNode:入口節點,特殊的鏈路節點,對應某個 Context 入口的所有調用數據。

如何使用Sentinel

引入依賴

我們通過maven將Sentinel依賴引入到項目中

Note: Sentinel requires Java 7 or later.
需要java7 或者更高的版本

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.7.1</version>
</dependency>

定義資源

定義資源的方式有五種

  • 主流框架的默認適配方式
    對於大部分主流框架,如Web Selvet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor等都做了適配,只需要引入對應的依賴既可以方便的的整合Sentinel。
    主流框架適配手冊
  • 拋出異常的方式

SphU 包含了 try-catch 風格的 API。用這種方式,當資源發生了限流之後會拋出 BlockException。這個時候可以捕捉異常,進行限流之後的邏輯處理。示例代碼如下:

 // 1.5.0 版本開始可以利用 try-with-resources 特性
// 資源名可使用任意有業務語義的字符串,比如方法名、接口名或其它可唯一標識的字符串。
try (Entry entry = SphU.entry("resourceName")) {
  // 被保護的業務邏輯
  // do something here...
} catch (BlockException ex) {
  // 資源訪問阻止,被限流或被降級
  // 在此處進行相應的處理操作
}

特別地,若 entry 的時候傳入了熱點參數,那麼 exit 的時候也一定要帶上對應的參數(exit(count, args)),否則可能會有統計錯誤。這個時候不能使用 try-with-resources 的方式。另外通過 Tracer.trace(ex) 來統計異常信息時,由於 try-with-resources 語法中 catch 調用順序的問題,會導致無法正確統計異常數,因此統計異常信息時也不能在 try-with-resources 的 catch 塊中調用 Tracer.trace(ex)。
手動 exit 示例:

Entry entry = null;
// 務必保證finally會被執行
try {
  // 資源名可使用任意有業務語義的字符串
  entry = SphU.entry("自定義資源名");
  // 被保護的業務邏輯
  // do something...
} catch (BlockException e1) {
  // 資源訪問阻止,被限流或被降級
  // 進行相應的處理操作
} finally {
  if (entry != null) {
    entry.exit();
  }
}

SphU.entry() 的參數描述:
參數名 類型 解釋 默認值
entryType EntryType 資源調用的流量類型,是入口流量(EntryType.IN)還是出口流量(EntryType.OUT),注意系統規則只對 IN 生效 EntryType.OUT
count int 本次資源調用請求的 token 數目 1
args Object[] 傳入的參數,用於熱點參數限流 無
注意:SphU.entry(xxx) 需要與 entry.exit() 方法成對出現,匹配調用,否則會導致調用鏈記錄異常,拋出 ErrorEntryFreeException 異常。常見的錯誤:
自定義埋點只調用 SphU.entry(),沒有調用 entry.exit()
順序錯誤,比如:entry1 -> entry2 -> exit1 -> exit2,應該爲 entry1 -> entry2 -> exit2 -> exit1

  • 返回布爾值的方式

SphO 提供 if-else 風格的 API。用這種方式,當資源發生了限流之後會返回 false,這個時候可以根據返回值,進行限流之後的邏輯處理。示例代碼如下:

 // 資源名可使用任意有業務語義的字符串
  if (SphO.entry("自定義資源名")) {
    // 務必保證finally會被執行
    try {
      /**
      * 被保護的業務邏輯
      */
    } finally {
      SphO.exit();
    }
  } else {
    // 資源訪問阻止,被限流或被降級
    // 進行相應的處理操作
  }

注意:SphO.entry(xxx) 需要與 SphO.exit()方法成對出現,匹配調用,位置正確,否則會導致調用鏈記錄異常,拋出ErrorEntryFreeException` 異常。

  • 註解方式

使用註解方式代碼侵入性太強,不太建議使用,官方介紹如下
Sentinel 支持通過 @SentinelResource 註解定義資源並配置 blockHandler 和 fallback 函數來進行限流之後的處理。示例:

// 原本的業務方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
    throw new RuntimeException("getUserById command failed");
}

// blockHandler 函數,原方法調用被限流/降級/系統保護的時候調用
public User blockHandlerForGetUser(String id, BlockException ex) {
    return new User("admin");
}

注意 blockHandler 函數會在原方法被限流/降級/系統保護的時候調用,而 fallback 函數會針對所有類型的異常。請注意 blockHandler 和 fallback 函數的形式要求,更多指引可以參見 Sentinel 註解支持文檔。

註解支持文檔

  • 異步調用支持在這裏插入代碼片

Sentinel 支持異步調用鏈路的統計。在異步調用中,需要通過 SphU.asyncEntry(xxx) 方法定義資源,並通常需要在異步的回調函數中調用 exit 方法。以下是一個簡單的示例:
SphU.asyncEntry(xxx) 不會影響當前(調用線程)的 Context,因此以下兩個 entry 在調用鏈上是平級關係(處於同一層),而不是嵌套關係:

try {
    AsyncEntry entry = SphU.asyncEntry(resourceName);

    // 異步調用.
    doAsync(userId, result -> {
        try {
            // 在此處處理異步調用的結果.
        } finally {
            // 在回調結束後 exit.
            entry.exit();
        }
    });
} catch (BlockException ex) {
    // Request blocked.
    // Handle the exception (e.g. retry or fallback).
}

若在異步回調中需要嵌套其它的資源調用(無論是 entry 還是 asyncEntry),只需要藉助 Sentinel 提供的上下文切換功能,在對應的地方通過 ContextUtil.runOnContext(context, f) 進行 Context 變換,將對應資源調用處的 Context 切換爲生成的異步 Context,即可維持正確的調用鏈路關係。示例如下:

public void handleResult(String result) {
    Entry entry = null;
    try {
        entry = SphU.entry("handleResultForAsync");
        // Handle your result here.
    } catch (BlockException ex) {
        // Blocked for the result handler.
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }
}

public void someAsync() {
    try {
        AsyncEntry entry = SphU.asyncEntry(resourceName);

        // Asynchronous invocation.
        doAsync(userId, result -> {
            // 在異步回調中進行上下文變換,通過 AsyncEntry 的 getAsyncContext 方法獲取異步 Context
            ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
                try {
                    // 此處嵌套正常的資源調用.
                    handleResult(result);
                } finally {
                    entry.exit();
                }
            });
        });
    } catch (BlockException ex) {
        // Request blocked.
        // Handle the exception (e.g. retry or fallback).
    }
}

定義規則

在定義好資源後,Sentinel需要我們提供限流規則。Sentinel所有的規則都可以在內存中查詢和修改,且修改後立即生效。
Sentinel支持的限流規則有:

  • 流量控制規則
  • 熔斷降級規則
  • 系統保護規則
  • 來源訪問控制規則
  • 熱點參數規則
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章