天天看點

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

什麼是sentinel?

Sentinel: 分布式系統的流量防衛兵

Sentinel 具有以下特征:

  • 豐富的應用場景:Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷、叢集流量控制、實時熔斷下遊不可用應用等。
  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況。
  • 廣泛的開源生态:Sentinel 提供開箱即用的與其它開源架構/庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。

    完善的 SPI 擴充點:Sentinel 提供簡單易用、完善的 SPI 擴充接口。您可以通過實作擴充接口來快速地定制邏輯。例如定制規則管理、适配動态資料源等。

Sentinel 的主要特性:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

Sentinel 分為兩個部分:

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

github位址

中文介紹

安裝Sentinel

  • 首先去下載下傳,位址
    SpringCloud Alibaba Sentinel實作熔斷與限流(上)
  • 然後運作,運作指令
java -jar sentinel-dashboard-1.8.2.jar
           

前提是有jdk環境,并且8080端口不能被占用

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

然後去通路

http://localhost:8080

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

使用者名密碼都是sentinel

項目整合sentinel

  • 建立子產品

    cloudalibaba-sentinel-service8401

    SpringCloud Alibaba Sentinel實作熔斷與限流(上)
  • 修改pom檔案,添加以下的依賴
<dependencies>
        <dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
            <groupId>com.zhubayi.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 後續做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web元件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>
           
SpringCloud Alibaba Sentinel實作熔斷與限流(上)
  • 修改配置檔案
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服務注冊中心位址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard位址
        dashboard: localhost:8080
        #預設8719端口,假如被占用會自動從8719開始依次+1掃描,直至找到未被占用的端口
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'
           
SpringCloud Alibaba Sentinel實作熔斷與限流(上)
  • 建立

    MainApp8401

    主啟動類
package com.zhubayi.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}

           
  • 建立

    FlowLimitController

package com.zhubayi.springcloud.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;



@RestController
public class FlowLimitController
{

    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}
           
SpringCloud Alibaba Sentinel實作熔斷與限流(上)

然後啟動Sentinel8080

java -jar sentinel-dashboard-1.8.2.jar
           

登入進去發現啥都沒有

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

因為Sentinel采用的懶加載,當有通路時才會加載,是以執行一次通路即可

http://localhost:8401/testA

http://localhost:8401/testB

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

說明sentinel8080正在監控微服務8401。

流控規則

1.基本介紹

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

解釋說明:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

2. 流控模式

(1) 直接(預設)

  • 就是快速失敗,直接不讓通路了,這是

    系統預設

  • 配置說明
    SpringCloud Alibaba Sentinel實作熔斷與限流(上)

表示1秒鐘内查詢1次就是OK,若超過次數1,就直接-快速失敗,報預設錯誤

測試:快速點選通路

http://localhost:8401/testA

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

直接調用預設報錯資訊

(2) 關聯

關聯是啥意思?

  • 當關聯的資源達到門檻值時,就限流自己。例如:當與A關聯的資源B達到閥值後,就限流A自己。B惹事,A挂了
  • 配置A
    SpringCloud Alibaba Sentinel實作熔斷與限流(上)

說明:當關聯資源/testB的qps閥值超過1時,就限流/testA的Rest通路位址,當關聯資源到門檻值後限制配置好的資源名

postman模拟并發密集通路testB

SpringCloud Alibaba Sentinel實作熔斷與限流(上)
SpringCloud Alibaba Sentinel實作熔斷與限流(上)

開始運作然後去通路

testA

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

可以看出,大批量線程高并發通路B,導緻A失效了

(3) 鍊路

鍊路流控模式指的是,當從某個接口過來的資源達到限流條件時,開啟限流。它的功能有點類似于針對來源配置項,差別在于:針對來源是針對上級微服務,而鍊路流控是針對上級接口,也就是說它的粒度更細。

這是重點講的内容 畢竟在這裡踩過坑

我用的版本是springCloud-alibab 是2.2.5.RELEASE sentinel1.8.0 是以會造成流控鍊路失效

給出解決辦法

Sentinel 鍊路流控模式失效

禁止收斂URL的入口context

從1.6.3 版本開始,Sentinel Web filter預設收斂所有URL的入口context,是以鍊路限流不生效。

1.7.0 版本開始(對應SCA的2.1.1.RELEASE),官方在CommonFilter 引入了

WEB_CONTEXT_UNIFY 參數,用于控制是否收斂context。将其配置為 false 即可根據不同的URL 進行鍊路限流。

SCA 2.1.1.RELEASE之後的版本,可以通過配置spring.cloud.sentinel.web-context-unify=false即可關閉收斂

我們目前使用的版本是SpringCloud Alibaba 2.2.5.RELEASE,無法實作鍊路限流。

新增service接口

package com.zhubayi.springcloud.alibaba.serivce;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;

@Service
public class MySentinelService {

    /**
     * @SentinelResource: 可以了解就是一個資源名
     */
    @SentinelResource(value = "myresource",blockHandler = "testAFallback")
    public String sentinelChain() {
        return "調用該資源成功!!!!!";
    }
    public String testAFallback(BlockException ex) {
        return "ex testA";
    }
}

           
  • controller
package com.zhubayi.springcloud.alibaba.controller;

import com.zhubayi.springcloud.alibaba.serivce.MySentinelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;



@RestController
public class FlowLimitController
{
    @Autowired
    private MySentinelService mySentinelService;

    @GetMapping("/testA")
    public String testA()
    {

        return "------testA"+mySentinelService.sentinelChain();
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB"+mySentinelService.sentinelChain();
    }

}
           

如果單單是這樣的配置 是不起效果的 還需要新增配置

1.7.0 版本開始(對應Spring Cloud Alibaba的2.1.1.RELEASE) 需要新增依賴

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
        </dependency>
           
SpringCloud Alibaba Sentinel實作熔斷與限流(上)

然後配置

spring.cloud.sentinel.web-context-unify=false

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

配置類

FilterContextConfig

package com.zhubayi.springcloud.alibaba.config;


import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        // 入口資源關閉聚合
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registrationBean.setName("sentinelFilter");
        registrationBean.setOrder(1);

        return registrationBean;

    }
}
           

接下來就有效果了

SpringCloud Alibaba Sentinel實作熔斷與限流(上)
SpringCloud Alibaba Sentinel實作熔斷與限流(上)

測試:頻繁通路testA會報錯,而通路testB則無影響。

SpringCloud Alibaba Sentinel實作熔斷與限流(上)
SpringCloud Alibaba Sentinel實作熔斷與限流(上)

3.流控效果

(1)直接->快速失敗

  • 這時預設的處理方式,預設的流控處理
  • 直接失敗,抛出異常->Blocked by Sentinel (flow limiting)
  • 源碼:

    com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

(2) Warm up 預熱

當流量突然增大的時候,我們常常會希望系統從空閑狀态到繁忙狀态的切換的時間長一些。即如果系統在此之前長期處于空閑的狀态,我們希望處理請求的數量是緩步的增多,經過預期的時間以後,到達系統處理請求個數的最大值。Warm Up(冷啟動,預熱)模式就是為了實作這個目的的。

預設 coldFactor 為 3,即請求 QPS 從 threshold / 3 開始,經預熱時長逐漸升至設定的 QPS 門檻值。

公式:門檻值除以coldFactor(預設值為3),經過預熱時長後才會達到門檻值

例如:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

上面的是官方說法 說人話就是

10/3=3

,即剛開始的門檻值為3

你一開始請求超過

每秒3次

則報錯 等預熱

5秒鐘

,5秒之後,

超過每秒10次

系統報錯,若不超過每秒10次,則正常運作

比如你要跑100米 得先熱熱身 讓身體适應一下 不然抽筋猝死就gg了

應用場景: 秒殺系統在開啟的瞬間,會有很多流量上來,很有可能把系統打死,預熱方式就是把為了保護系統,可慢慢的把流量放進來,慢慢的把閥值增長到設定的閥值。

官方冷啟動說明

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預熱/冷啟動方式。當系統長期處于低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。通過"冷啟動",讓通過的流量緩慢增加,在一定時間内逐漸增加到門檻值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。詳細文檔可以參考 流量控制 - Warm Up 文檔,具體的例子可以參見 WarmUpFlowDemo。

通常冷啟動的過程系統允許通過的 QPS 曲線如下圖所示:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

(3)排隊等待

官方文檔

勻速排隊(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。詳細文檔可以參考 流量控制 - 勻速器模式,具體的例子可以參見 PaceFlowDemo。

該方式的作用如下圖所示:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

這種方式主要用于處理間隔性突發的流量,例如消息隊列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處于空閑狀态,我們希望系統能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多餘的請求。

注意:勻速排隊模式暫時不支援 QPS > 1000 的場景。

例如:

SpringCloud Alibaba Sentinel實作熔斷與限流(上)

說明:

勻速排隊,讓請求以均勻的速度通過,閥值類型必須設成QPS,否則無效。

設定含義:/testA每秒1次請求,超過的話就排隊等待,等待的逾時時間為20000毫秒,超過則報錯。