10000字,圖解分散式系統限流平臺Sentinel

張哥說技術發表於2023-04-07

大家好,我是哪吒。

Sentinel是阿里巴巴開源的一款輕量級流量控制、熔斷降級工具,它提供了實時的流量控制,熔斷降級等功能,能夠幫助我們實現服務的高可用性和穩定性。

本文將會介紹Sentinel的作用和優勢、快速開始、進階使用、Spring Cloud Alibaba Sentinel整合以及實踐案例,並對Sentinel的侷限和不足進行分析

一、前言

1、關於 Sentinel

Sentinel 是阿里巴巴開源的一款針對分散式系統的流量控制、熔斷降級的框架。在微服務架構的系統中,請求流量複雜多樣,可能會因為某一個服務異常而導致整體服務不可用,這時候需要熔斷降級,而 Sentinel 就提供了這樣的解決方案。

10000字,圖解分散式系統限流平臺Sentinel

2、Sentinel 的作用和優勢

Sentinel 可以針對服務方法呼叫、HTTP 請求、Dubbo 服務等,進行實時的流量控制、熔斷降級,確保服務高可用,同時還可以提供實時的監控和報警功能

Sentinel 有以下一些優勢:

  1. 豐富的應用場景和細粒度的控制: Sentinel 支援多種應用場景,包括熔斷降級、流量控制、系統保護、熱點引數限流等,而且可以實現細粒度的控制;
  2. 強大的實時監測機制: Sentinel 提供了實時的監測、報警機制,能夠對系統執行情況進行實時檢測和通知,發現問題更加及時;
  3. 易於擴充套件: Sentinel 為開發者提供了簡單易用的擴充套件介面,開發者可以方便的實現自定義的控制和監測邏輯;
  4. 易於整合: Sentinel 支援多種開發框架,包括 Spring Cloud、Dubbo、Feign 等,開發者可以很方便的將 Sentinel 整合到自己的應用中;

3、本文目的和內容概述

本文將為讀者介紹 Sentinel 的基礎和進階使用方法,包括

  1. 如何配置 Sentinel 控制檯;
  2. 如何編寫並測試 Sentinel 規則、如何使用自定義 Sentinel 規則擴充套件開發;
  3. 介紹 Sentinel 和 Spring Cloud Alibaba 的整合方法,並且給出了一些 Sentinel 實踐案例供讀者參考。

本文的目的是幫助讀者快速上手使用 Sentinel,並且深入理解其基本原理和使用方法。同時,也希望能夠對讀者們的日常工作有所幫助。

二、快速開始

1、環境準備

在開始使用 Sentinel 之前,我們需要準備好以下環境:

  1. JDK 1.8 或更高版本
  2. Maven 3.0 或更高版本
  3. Sentinel-dashboard

2、引入 Sentinel 依賴

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

3、配置 Sentinel 控制檯

在Sentinel的官網下載最新的控制檯jar包,然後在控制檯目錄下執行以下命令啟動控制檯:

java -jar sentinel-dashboard-1.8.2.jar

啟動成功後,可以透過瀏覽器訪問檢視控制檯頁面。

4、註冊應用到 Sentinel 控制檯

在應用啟動類上新增註解@EnableSentinel註解,然後在配置檔案中配置應用名稱和Sentinel控制檯的地址:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel
            groupId: DEFAULT_GROUP
            data-type: json

5、編寫並測試 Sentinel 規則

Sentinel提供了多種限流降級策略,本文以流控規則為例進行演示。

在需要限流的方法上新增@SentinelResource註解,然後配置流控規則:

@GetMapping("/hello")
@SentinelResource(value = "hello", blockHandler = "blockHandler")
public String hello() {
    return "Hello, World!";
}

public String blockHandler(BlockException e) {
    return "請求過於頻繁,請稍後重試!";
}

在控制檯的流控規則頁面新增對應的規則,設定好閾值和統計視窗等引數,然後測試該介面。

三、進階使用

1、Sentinel Dashboard 使用詳解

Sentinel Dashboard是Sentinel的視覺化監控平臺,可以用於實時監控應用的流量、延遲、異常等指標,並對應用進行限流降級等操作

10000字,圖解分散式系統限流平臺Sentinel

Sentinel客戶端首先向Sentinel Dashboard註冊。Sentinel Dashboard返回一個token給客戶端,客戶端將使用該token連線Sentinel。

應用程式將使用token連線Sentinel,Sentinel客戶端將返回連線成功資訊。Sentinel客戶端將實時推送metrics資料到Sentinel Dashboard,Sentinel Dashboard將監控和管理應用程式。

2、入門級規則配置詳解(流控規則、降級規則、熱點引數限流)

Sentinel是一款開源的流量控制和降級框架,提供多種限流降級策略,包括流控規則、降級規則、熱點引數限流等。

下面將逐一介紹這些規則。

(1)流控規則

流控規則用於限制系統的流量,可以透過設定QPS流量控制和執行緒數流量控制等方式來控制系統的訪問速度。

在Sentinel Dashboard中,可以透過以下步驟來配置和管理流控規則:

  • 設定流控模式:可以選擇直接拒絕、Warm Up、勻速排隊等模式。
  • 設定閾值:可以設定QPS、執行緒數等閾值來限制流量。
  • 設定流控策略:可以選擇按照呼叫關係、鏈路入口等策略來限制流量。
  • 檢視已有規則:可以檢視已經存在的流控規則,並進行管理和修改。
(2)降級規則

降級規則用於應對系統的異常情況,可以透過設定異常比例降級、異常數降級和慢呼叫降級等方式來降低系統的負載。

在Sentinel Dashboard中,可以透過以下步驟來配置和管理降級規則:

  • 設定降級模式:可以選擇異常比例、異常數和慢呼叫三種模式。
  • 設定閾值:可以設定異常比例、異常數和慢呼叫時間等閾值來觸發降級。
  • 設定降級策略:可以選擇返回特定的錯誤資訊、呼叫備用服務等策略來處理降級情況。
  • 檢視已有規則:可以檢視已經存在的降級規則,並進行管理和修改。
(3)熱點引數限流

熱點引數限流用於對熱點引數進行限流,可以有效避免某些引數被過多地請求。在Sentinel Dashboard中,可以透過以下步驟來配置和管理熱點引數限流規則:

  • 設定引數:可以選擇需要進行限流的引數。
  • 設定閾值:可以設定QPS、執行緒數等閾值來限制熱點引數的訪問速度。
  • 設定限流策略:可以選擇直接拒絕、勻速排隊等策略來處理熱點引數限流。
  • 檢視已有規則:可以檢視已經存在的熱點引數限流規則,並進行管理和修改。

在使用這些規則時,需要注意引數設定和閾值設定等細節,以避免規則的誤判或限流不準確等問題。

透過Sentinel Dashboard的視覺化介面,可以方便地進行規則的配置和管理,提高系統的穩定性和可靠性

3、資源名與 URL 匹配規則

Sentinel的資源名和URL匹配規則是限流降級策略的重要組成部分,可以根據業務需求定義合適的匹配規則。

  • 資源名:可以是一個具體的業務方法、一個介面URL或者一個Dubbo服務等。
  • URL 匹配規則:支援Ant匹配和正則匹配兩種方式,可以根據具體需求進行選擇。
  • Dubbo服務:Sentinel支援對Dubbo服務進行限流降級操作,需要在Dubbo配置檔案中新增Sentinel的攔截器配置。
  • 在定義資源名和URL匹配規則時,需要注意合理性和精確性,以避免出現誤判或限流不準確等問題。
10000字,圖解分散式系統限流平臺Sentinel

上圖展示了應用程式程式碼中定義資源名和 URL 匹配規則時的互動過程。

應用程式透過 Sentinel 客戶端向 Sentinel 傳送配置請求,Sentinel 返回配置結果。應用程式根據配置結果使用 Sentinel 進行限流降級。

在這個過程中,應用程式需要注意合理性和精確性,以避免出現誤判或限流不準確等問題。

4、自定義 Sentinel 規則擴充套件開發

10000字,圖解分散式系統限流平臺Sentinel

上圖是自定義規則擴充套件的關係圖示。

自定義規則擴充套件包括資料來源擴充套件、限流降級規則擴充套件、規則統計擴充套件等,可以使用多種語言進行開發。

在進行規則擴充套件時,需要注意程式碼質量和效能,以保證擴充套件的準確性和有效性。

以下是一個自定義規則型別的示例:

public class CustomFlowRule implements FlowRule {
    
    private String resourceName;
    private int count;
    private int interval;
    
    public CustomFlowRule(String resourceName, int count, int interval) {
        this.resourceName = resourceName;
        this.count = count;
        this.interval = interval;
    }

    @Override
    public String getResource() {
        return resourceName;
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setCount(int count) {
        this.count = count;
    }

    @Override
    public int getInterval() {
        return interval;
    }

    @Override
    public void setInterval(int interval) {
        this.interval = interval;
    }
}

在這個示例中,我們自定義了一個 CustomFlowRule 型別,它包含了 resourceName、count 和 interval 三個屬性。同時,我們實現了 FlowRule 介面,並實現了其中的各個方法,以滿足 Sentinel 對規則型別的要求。

使用這個自定義規則型別時,我們需要在程式碼中新增相關的配置,例如:

List<CustomFlowRule> rules = new ArrayList<>();
CustomFlowRule rule = new CustomFlowRule("custom_resource"101);
rules.add(rule);
FlowRuleManager.loadRules(rules);

在這個示例中,我們透過 CustomFlowRule 型別建立了一個規則,它的資源名稱為 custom_resource,限流閾值為 10,時間間隔為 1 秒。然後我們將這個規則新增到 Sentinel 的規則管理器中,從而讓 Sentinel 能夠自動識別和使用這個規則。

四、Spring Cloud Alibaba Sentinel 整合

1、Sentinel Starter 簡介

Sentinel Starter是Spring Cloud Alibaba Sentinel的快速入門依賴,提供了自動化配置和預設規則等能力,可以簡化Sentinel在Spring Cloud中的使用。

在使用Sentinel Starter時,只需要新增依賴並在配置檔案中配置相應的引數,即可快速實現Sentinel的限流降級功能。

2、使用 Sentinel Starter 整合 Spring Cloud 微服務

(1)在Spring Boot專案中新增以下依賴:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)在application.yml配置檔案中新增以下配置:
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # Sentinel控制檯地址
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848 # Nacos配置中心地址
            dataId: ${spring.application.name}-sentinel # Sentinel配置資料ID
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow,degrade # Sentinel規則型別
(3)在程式碼中新增註解 @EnableSentinel ,開啟 Sentinel 功能。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableSentinel // 開啟 Sentinel 功能
public class ProductServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.classargs);
    }
}
(4)使用註解 @SentinelResource 對需要進行限流和降級的介面進行配置。
@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products/{id}")
    @SentinelResource(value = "products/{id}", blockHandlerClass = ProductControllerBlockHandler.classblockHandler "handleBlock")
    public Product getProduct(@PathVariable Long id) {
        return productService.getProduct(id);
    }
}

其中,@SentinelResource 註解中的 value 引數為資源名稱,blockHandlerClass 和 blockHandler 分別指定了限流或降級時的處理類和方法。

3、限流和降級策略在微服務中的應用場景

10000字,圖解分散式系統限流平臺Sentinel

在上圖中,我們可以看到當服務請求量過大時,API Gateway 可以對服務進行限流,避免服務過載。同時,當某個服務出現故障或負載過高時,可以對該服務進行降級,避免影響其他服務的正常執行。

4、示例程式碼

(1)新增 @SentinelResource 註解
@RestController
public class OrderController {

    @PostMapping("/createOrder")
    @SentinelResource(value = "createOrder", blockHandlerClass = OrderBlockHandler.classblockHandler "handleBlock")
    public Result createOrder(@RequestBody OrderRequest orderRequest) {
        // ...
    }
}
(2)新增 @Idempotent 註解
@RestController
public class OrderController {

    @PostMapping("/createOrder")
    @SentinelResource(value = "createOrder", blockHandlerClass = OrderBlockHandler.classblockHandler "handleBlock")
    @Idempotent(key = "#orderRequest.userId + ':' + #orderRequest.productId")
    public Result createOrder(@RequestBody OrderRequest orderRequest) {
        // ...
    }
}
(3)實現冪等性校驗邏輯
@Component
public class OrderService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean checkIdempotency(String key) {
        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, "1");
        if (result != null && result) {
            redisTemplate.expire(key, 60, TimeUnit.SECONDS);
            return true;
        }
        return false;
    }
}

五、基於 Sentinel 的分散式鎖實現

1、場景描述

假設我們有一個高併發的秒殺系統,我們需要實現分散式鎖來控制同一時間只能有一個使用者參與秒殺活動。為了防止死鎖和死節點,我們使用 Sentinel 的分散式鎖實現來保證系統的可用性和穩定性。

10000字,圖解分散式系統限流平臺Sentinel

2、實現步驟

(1)新增 Sentinel 的依賴到專案中:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)在配置檔案中新增 Sentinel 的配置:
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
(3)在程式碼中使用 Sentinel 的分散式鎖實現:
@RestController
public class SeckillController {

    @Autowired
    private DistributedLock distributedLock;

    @GetMapping("/seckill")
    public String seckill(@RequestParam("userId") Long userId,
                          @RequestParam("itemId") Long itemId) 
{
        // 獲取鎖
        String lockKey = "seckill:" + itemId;
        boolean locked = distributedLock.tryLock(lockKey);
        if (!locked) {
            return "Failed to get lock";
        }
        try {
            // 執行秒殺邏輯
            return "Success";
        } finally {
            // 釋放鎖
            distributedLock.unlock(lockKey);
        }
    }
}

在 Sentinel 控制檯中建立流控規則,限制流量:

  • 在 Dashboard 中建立應用
  • 在 Flow 中建立規則,設定限制流量的策略,例如:QPS 為 1000。

示例程式碼:

@Component
public class DistributedLock {

    private static final String LOCK_PREFIX = "distributed-lock:";

    @Autowired
    private CuratorFramework curatorFramework;

    public boolean tryLock(String key) {
        String lockPath = LOCK_PREFIX + key;
        InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
        try {
            return lock.acquire(1, TimeUnit.SECONDS);
        } catch (Exception ex) {
            throw new RuntimeException("Failed to acquire lock", ex);
        }
    }

    public void unlock(String key) {
        String lockPath = LOCK_PREFIX + key;
        InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
        try {
            lock.release();
        } catch (Exception ex) {
            throw new RuntimeException("Failed to release lock", ex);
        }
    }
}

六、基於 Sentinel 的 A/B 測試實現

1、場景描述

假設我們有一個電商網站,想要測試一個新的促銷活動頁面對使用者購買行為的影響。我們希望將使用者隨機分為兩個組,其中一個組將看到新的促銷頁面,另一個組將看到舊的促銷頁面。我們希望透過分析兩組使用者的購買轉化率來確定新頁面是否對提高購買轉化率有幫助。

2、實現步驟

  1. 根據使用者的請求特徵將請求分組,例如使用 @SentinelResource 的 blockHandlerClass 和 blockHandler 指定請求被限流或降級時的處理類和方法,處理類中可以根據請求的特徵將請求分組。
  2. 在新的促銷頁面和舊的促銷頁面中分別新增上報程式碼,將使用者的購買行為和分組資訊上報到 Sentinel。
  3. 在 Sentinel 控制檯中建立一個流控規則,將兩個組的流量分別限制在一定的範圍內,確保兩組之間的請求量基本相等。
  4. 分析兩組使用者的購買轉化率,確定新頁面是否對提高購買轉化率有幫助。
10000字,圖解分散式系統限流平臺Sentinel

3、示例程式碼

(1)根據請求特徵將請求分組
@RestController
public class PromotionController {
    
    @GetMapping("/promotion")
    @SentinelResource(value = "promotion", blockHandlerClass = PromotionBlockHandler.classblockHandler "handle")
    public String promotion(@RequestParam("userId") Long userId) {
        // 根據使用者 id 判斷使用者應該分到哪個組
        int groupId = userId % 2;
        return "Group " + groupId;
    }
}

@Component
public class PromotionBlockHandler {
    
    public String handle(Long userId, BlockException ex) {
        // 處理限流或降級情況下的邏輯
        int groupId = userId % 2;
        return "Blocked Group " + groupId;
    }
}
(2)將使用者的購買行為和分組資訊上報到 Sentinel
@RestController
public class PromotionController {
    
    @GetMapping("/promotion")
    @SentinelResource(value = "promotion", blockHandlerClass = PromotionBlockHandler.classblockHandler "handle")
    public String promotion(@RequestParam("userId") Long userId, @RequestParam("itemId") Long itemId) {
        // 根據使用者 id 判斷使用者應該分到哪個組
        int groupId = userId % 2;
        
        // 上報使用者購買行為和分組資訊
        String resourceName = "promotion_" + itemId;
        Entry entry = null;
        try {
            entry = SphU.entry(resourceName);
            Tracer.traceEntry("group_id=" + groupId);
            // 執行業務邏輯
            return "Success";
        } catch (BlockException ex) {
            // 處理限流或降級情況下的邏輯
            return "Blocked Group " + groupId;
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
}
(3)在 Sentinel 控制檯中建立流控規則

在 Sentinel 控制檯中建立兩個流控規則,將兩個組的流量分別限制在一定的範圍內,可以透過配置在限流規則中新增特定的引數,如 group_id=0 和 group_id=1,來將不同組的請求進行區分。

示例程式碼:

  1. 在 Sentinel 控制檯中建立流控規則
  2. 開啟 Sentinel 控制檯,進入流控規則頁面;
  3. 點選 “新建” 按鈕,填寫如下資訊:
規則名稱:promotion_flow_control;

資源名:promotion_*;

限流閾值:100

流控模式:QPS;

應用名稱:default

引數:group_id=0

點選 "提交" 按鈕,建立一個限制組 0 的流控規則;

點選 "新建" 按鈕,填寫如下資訊:

規則名稱:promotion_flow_control;

資源名:promotion_*;

限流閾值:100

流控模式:QPS;

應用名稱:default

引數:group_id=1

點選 “提交” 按鈕,建立一個限制組 1 的流控規則;

注意事項:

在使用 Sentinel 進行 A/B 測試時,需要注意以下幾個方面:

  1. 將請求進行隨機分組,確保兩個組之間的請求量基本相等;
  2. 在 Sentinel 控制檯中建立流控規則,限制每個組的流量,確保流量控制的精度和正確性;
  3. 在上報資料時,需要將使用者的分組資訊和購買行為一併上報,以便後續的資料分析;
  4. 在分析資料時,需要根據不同組的資料進行對比,確保分析結果的準確性。

七、總結

1、Sentinel 的侷限和不足

Sentinel雖然具有很多優點和優勢,但也存在一些侷限和不足。

例如,Sentinel對業務程式碼的侵入性較大,需要在程式碼中新增相關的註解或者攔截器等;同時,Sentinel的配置較為複雜,需要進行多種規則的配置和引數的調整等。

此外,Sentinel還存在一些效能問題和安全問題,需要注意規避和解決。

2、Sentinel 的發展前景

儘管Sentinel存在一些不足和侷限,但隨著微服務和雲原生技術的普及和發展,Sentinel在限流降級等方面的需求和重要性將會越來越大

同時,Sentinel也在不斷地進行最佳化和改進,例如在效能和安全方面進行了多項最佳化和加強,同時還提供了更加方便和高效的規則擴充套件開發能力,可以滿足不同業務場景的需求。

因此,Sentinel在未來的發展中將會發揮越來越重要的作用,成為雲原生技術生態圈中的一顆明珠。

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

相關文章