天天看點

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

Sentinel 的使用可以分為兩個部分:

  • 核心庫(Java 用戶端):不依賴任何架構/庫,能夠運作于 Java 7 及以上的版本的運作時環境,同時對 Dubbo / Spring Cloud 等架構也有較好的支援(見 主流架構适配)。
  • 控制台(Dashboard):控制台主要負責管理推送規則、監控、叢集限流配置設定管理、機器發現等。

1. 引入 Sentinel 依賴

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

2. 入門案例

資源 是 Sentinel 中的核心概念之一。最常用的資源是我們代碼中的 Java 方法。 當然,您也可以更靈活的定義你的資源,例如,把需要控制流量的代碼用 Sentinel API

SphU.entry("HelloWorld")

entry.exit()

包圍起來即可。在下面的例子中,我們将

System.out.println("hello world");

作為資源(被保護的邏輯),用 API 包裝起來。參考代碼如下:

SentinelService.java

package cn.javayuli.service;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 限流測試
 * @author hanguilin
 */
@Service
public class SentinelService {

    /**
     * 處理請求
     */
    public void handleRquest() {
        // 配置規則.
        initFlowRules();

        // 1.5.0 版本開始可以直接利用 try-with-resources 特性,自動 exit entry
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保護的邏輯
            System.out.println("hello world");
        } catch (BlockException ex) {
            // 處理被流控的邏輯
            System.out.println("blocked!");
        }
    }

    /**
     * 配置流控規則, QPS最大20
     */
    private void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}
           

SentinelController.java

package cn.javayuli.controller;

import cn.javayuli.service.SentinelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 限流測試
 * @author hanguilin
 */
@RestController
public class SentinelController {

    @Autowired
    private SentinelService sentinelService;

    /**
     * 請求資源
     */
    @GetMapping("getSource")
    public void doGetSource () {
        sentinelService.handleRquest();
    }

}
           

3.檢查結果

啟動項目,并使用Jmeter進行壓測

配置1秒發送18個請求

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

配置通路接口

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

控制台正常列印

hello world

現在把18調成30,發現已經被鎖住了

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

Demo 運作之後,我們可以在日志

${currentUser}/logs/csp/${appName}-metrics.log.xxx

裡看到下面的輸出:

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台
|--timestamp-|------date time----|--resource-|p |block|s |e|rt
1608555871000|2020-12-21 21:04:31|/getSource|10|0|10|0|42|0|0|1
1608555871000|2020-12-21 21:04:31|HelloWorld|10|0|10|0|0|0|0|0
1608555871000|2020-12-21 21:04:31|__total_inbound_traffic__|10|0|10|0|42|0|0|0
1608555872000|2020-12-21 21:04:32|/getSource|20|0|20|0|1|0|0|1
1608555872000|2020-12-21 21:04:32|HelloWorld|15|5|15|0|0|0|0|0
1608555872000|2020-12-21 21:04:32|__total_inbound_traffic__|20|0|20|0|1|0|0|0
           

其中

p

代表通過的請求,

block

代表被阻止的請求,

s

代表成功執行完成的請求個數,

e

代表使用者自定義的異常,

rt

代表平均響應時長。

4.熔斷降級

Sentinel 提供了

@SentinelResource

注解用于定義資源,并提供了 AspectJ 的擴充用于自動定義資源、處理

BlockException

@SentinelResource

用于定義資源,并提供可選的異常處理和 fallback 配置項。

@SentinelResource

注解包含以下屬性:

  • value

    :資源名稱,必需項(不能為空)
  • entryType

    :entry 類型,可選項(預設為

    EntryType.OUT

  • blockHandler

    /

    blockHandlerClass

    :

    blockHandler

    對應處理

    BlockException

    的函數名稱,可選項。blockHandler 函數通路範圍需要是

    public

    ,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為

    BlockException

    。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定

    blockHandlerClass

    為對應的類的

    Class

    對象,注意對應的函數必需為 static 函數,否則無法解析。
  • fallback

    /

    fallbackClass

    :fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了

    exceptionsToIgnore

    裡面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:
    • 傳回值類型必須與原函數傳回值類型一緻;
    • 方法參數清單需要和原函數一緻,或者可以額外多一個

      Throwable

      類型的參數用于接收對應的異常。
    • fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定

      fallbackClass

      為對應的類的

      Class

      對象,注意對應的函數必需為 static 函數,否則無法解析。
  • defaultFallback

    (since 1.6.0):預設的 fallback 函數名稱,可選項,通常用于通用的 fallback 邏輯(即可以用于很多服務或方法)。預設 fallback 函數可以針對所有類型的異常(除了

    exceptionsToIgnore

    裡面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則隻有 fallback 會生效。defaultFallback 函數簽名要求:
    • 傳回值類型必須與原函數傳回值類型一緻;
    • 方法參數清單需要為空,或者可以額外多一個

      Throwable

      類型的參數用于接收對應的異常。
    • defaultFallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定

      fallbackClass

      為對應的類的

      Class

      對象,注意對應的函數必需為 static 函數,否則無法解析。
  • exceptionsToIgnore

    (since 1.6.0):用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。

1.8.0 版本開始,

defaultFallback

支援在類級别進行配置。

注:1.6.0 之前的版本 fallback 函數隻針對降級異常(

DegradeException

)進行處理,不能針對業務異常進行處理。

特别地,若 blockHandler 和 fallback 都進行了配置,則被限流降級而抛出

BlockException

時隻會進入

blockHandler

處理邏輯。若未配置

blockHandler

fallback

defaultFallback

,則被限流降級時會将

BlockException

直接抛出(若方法本身未定義 throws BlockException 則會被 JVM 包裝一層

UndeclaredThrowableException

)。

從 1.4.0 版本開始,注解方式定義資源支援自動統計業務異常,無需手動調用

Tracer.trace(ex)

來記錄業務異常。Sentinel 1.4.0 以前的版本需要自行調用

Tracer.trace(ex)

來記錄業務異常。

配置

Spring Cloud Alibaba

若您是通過 Spring Cloud Alibaba 接入的 Sentinel,則無需額外進行配置即可使用

@SentinelResource

注解。

Spring AOP

若您的應用使用了 Spring AOP(無論是 Spring Boot 還是傳統 Spring 應用),您需要通過配置的方式将

SentinelResourceAspect

注冊為一個 Spring Bean:

@Configuration
public class SentinelAspectConfiguration {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}
           

我們提供了 Spring AOP 的示例,可以參見 sentinel-demo-annotation-spring-aop。

AspectJ

若您的應用直接使用了 AspectJ,那麼您需要在

aop.xml

檔案中引入對應的 Aspect:

<aspects>
    <aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
           

DEMO

系列源代碼GitHub位址spring-cloud-demo

代碼

/**
 * hello
 *
 * @param s
 * @return
 */
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
    if (s == 0) {
        throw new RuntimeException("error");
    }
    return String.format("Hello at %d", s);
}

/**
 * Fallback 函數,函數簽名與原函數一緻或加一個 Throwable 類型的參數.
 *
 * @param s
 * @return
 */
public String helloFallback(long s) {
    return String.format("Halooooo %d", s);
}

/**
 * Block 異常處理函數,參數最後多一個 BlockException,其餘與原函數一緻.
 *
 * @param s
 * @param ex
 * @return
 */
public String exceptionHandler(long s, BlockException ex) {
    // Do some log here.
    ex.printStackTrace();
    return "Oops, error occurred at " + s;
}
           

接口測試

傳入參數1

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

測試結果為正常調用的結果

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

參數0,測試結果為回調結果

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

5.Sentinel控制台

概述

Sentinel 提供一個輕量級的開源控制台,它提供機器發現以及健康情況管理、監控(單機和叢集),規則管理和推送的功能。另外,鑒權在生産環境中也必不可少。這裡,我們将會詳細講述如何通過簡單的步驟就可以使用這些功能。

接下來,我們将會逐一介紹如何整合 Sentinel 核心庫和 Dashboard,讓它發揮最大的作用。同時我們也在阿裡雲上提供企業級的控制台:AHAS Sentinel 控制台,您隻需要幾個簡單的步驟,就能最直覺地看到控制台如何實作這些功能。

Sentinel 控制台包含如下功能:

  • 檢視機器清單以及健康情況:收集 Sentinel 用戶端發送的心跳包,用于判斷機器是否線上。
  • 監控 (單機和叢集聚合):通過 Sentinel 用戶端暴露的監控 API,定期拉取并且聚合應用監控資訊,最終可以實作秒級的實時監控。
  • 規則管理和推送:統一管理推送規則。
  • 鑒權:生産環境中鑒權非常重要。這裡每個開發者需要根據自己的實際情況進行定制。
注意:Sentinel 控制台目前僅支援單機部署。

下載下傳

  • jar包可以在release頁面進行下載下傳
  • 或者下載下傳源碼,運作時需要自行打包
注意:啟動 Sentinel 控制台需要 JDK 版本為 1.8 及以上版本。

鑒權

從 Sentinel 1.5.0 開始,控制台提供通用的鑒權接口 AuthService,使用者可根據需求自行實作。

從 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登入功能,預設使用者名和密碼都是

sentinel

使用者可以通過如下參數進行配置:

  • -Dsentinel.dashboard.auth.username=sentinel

    用于指定控制台的登入使用者名為

    sentinel

  • -Dsentinel.dashboard.auth.password=123456

    用于指定控制台的登入密碼為

    123456

    ;如果省略這兩個參數,預設使用者和密碼均為

    sentinel

  • -Dserver.servlet.session.timeout=7200

    用于指定 Spring Boot 服務端 session 的過期時間,如

    7200

    表示 7200 秒;

    60m

    表示 60 分鐘,預設為 30 分鐘;

同樣也可以直接在 Spring properties 檔案中進行配置。

服務端

使用如下指令啟動控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
           

如若8080端口沖突,可使用

-Dserver.port=新端口

進行設定。

浏覽器打開localhost:8080,使用者名和密碼均為sentinel

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

用戶端

在application.yml中加入如下配置

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
           

如果是用nacos作為配置中心,需要在nacos中配置應用的配置檔案

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

使用

如果我們想使用Sentinel的限流和熔斷功能,除了在代碼中可以寫死外,也可直接通過控制台進行粗略的對接口進行限流和熔斷。

在Controller中加入測試方法,注意此Controller使用的時@RestController注解,如果是@Controller,請給方法加上@ResponseBody注解

/**
 * 請求資源
 */
@GetMapping("/testReq")
@SentinelResource("testSource")
public String doTest () {
    return "test";
}
           

先調用一次該方法,友善被簇點鍊路收集,調用後,可在控制台->簇點鍊路中看到該資源

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

點選

+流控

新增規則

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

使用Jmeter進行測試,每秒執行10個請求

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

http請求

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

發現此處通過QPS最大限定值後,其餘請求都被拒絕

SpringCloudAlibaba之Sentinel流控熔斷1. 引入 Sentinel 依賴2. 入門案例3.檢查結果4.熔斷降級5.Sentinel控制台

繼續閱讀