1. 程式人生 > 實用技巧 >Spring Cloud Alibaba 04:Sentinel 服務限流降級

Spring Cloud Alibaba 04:Sentinel 服務限流降級

雪崩效應

解決方案

1、設定執行緒超時

2、設定限流

3、熔斷器 Sentinel、Hystrix

1、pom.xml 引入依賴

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、application 配置

# actuator暴露所有端點
management:
  endpoints:
    web:
      exposure:
        include: '*'
# 與Sentinel DashBoard互動地址
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

3、下載 Sentinel 控制檯:https://github.com/alibaba/Sentinel/releases,啟動:java -jar sentinel-dashboard-1.8.0.jar

賬號密碼皆為sentinel,啟動nacos,啟動provider模組和consumer模組,訪問http://localhost:9090/index

1、流控規則

直接限流:直接對關聯的url資源限流

開啟sentinel,開啟provider服務

對/index資源做流控,設定QPS為1(表示一秒鐘只允許訪問一次)

當訪問一秒鐘訪問http://localhost:8001/index超過一次時,會限制顯示被流控限制阻塞

關聯限流:當被訪問的url資源超過設定的閾值,限流關聯的資源

controller新增list方法:

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

新增測試依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

需要同時範文資源才能看到效果,測試類對http://localhost:8001/index訪問

@Test
@DisplayName("測試關聯流控模式")
void test1() throws InterruptedException {
    RestTemplate restTemplate = new RestTemplate();
    for (int i = 0; i < 100; ++i) {
        restTemplate.getForObject("http://localhost:8081/index", String.class);
        System.out.println("provider==>/index=======>" + i);
        //休眠200毫秒
        TimeUnit.MILLISECONDS.sleep(200);
    }
}

啟動provider程式,設定流控規則如下:

設定完流控規則後啟動測試程式,瀏覽器訪問http://localhost:8001/list則出現以下情況,表示對index訪問超過閾值,則關聯資源list限流

鏈路限流:對更深層次資源限流(不僅僅侷限於controller)

1、pom.xml 新增依賴

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
</dependency>

2、application.yml

spring:
	cloud:
        sentinel:
          filter:
            enabled: false

3、寫配置類

package com.godfrey.configuration;

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;

import javax.servlet.Filter;

/**
 * @author godfrey
 * @since 2020-12-07
 */
@Configuration
public class FilterConfiguration {

    @Bean
    public FilterRegistrationBean<Filter> registrationBean() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registrationBean.setName("sentinelFilter");
        return registrationBean;
    }
}

4、Service

@Service
public class ProviderService {

    @SentinelResource("test")  //test 保護資源名
    public void test() {
        System.out.println("test");
    }
}

5、Controller

private final ProviderService providerService;

@Autowired
public ProviderController(ProviderService providerService) {
    this.providerService = providerService;
}

@GetMapping("/test1")
public String test1() {
    this.providerService.test();
    return "test1";
}

@GetMapping("/test2")
public String test2() {
    this.providerService.test();
    return "test2";
}

為了對比,test1做鏈路限流,對test2不做限流,設定如下

一秒鐘訪問http://localhost:8081/test1超過一次時,會對service繫結資源限流

訪問http://localhost:8081/test2則不會

2、流控效果

快速失敗

直接丟擲異常

Warm UP

給系統一個預熱的時間,預熱時間段內單機閾值較低,預熱時間過後單機閾值增加,預熱時間內當前的單機閾值是設定的閾值的三分之一,預熱時間過後單機閾值恢復設定的值。

排隊等待

當請求呼叫失敗之後,不會立即丟擲異常,等待下一次呼叫,時間範圍是超時時間,在時間範圍內如果請求則丟擲異常。閥值型別必須設成QPS,否則無效

3、降級規則

RT

單個請求的響應時間超過閾值,則進入準降級狀態,接下來 1 S 內連續 5 個請求響應時間均超過閾值,就進行降級,持續時間為時間視窗的值。

異常比例

每秒異常數量佔通過量的比例大於閾值,就進行降級處理,持續時間為時間視窗的值。

異常數

1 分鐘內的異常數超過閾值就進行降級處理,時間視窗的值要大於 60S,否則剛結束熔斷又進入下一次熔斷了。

4、熱點規則

熱點規則是流控規則的更細粒度操作,可以具體到對某個熱點引數的限流,設定限流之後,如果帶著限流引數的請求量超過閾值,則進行限流,時間為統計視窗時長。

必須要新增 @SentinelResource,即對資源進行流控。

@GetMapping("/hot")
@SentinelResource("hot")
public String hot(
        @RequestParam(value = "num1",required = false) Integer num1,
        @RequestParam(value = "num2",required = false) Integer num2){
    return num1+"-"+num2;
}

5、授權規則

給指定的資源設定流控應用(追加引數),可以對流控應用進行訪問許可權的設定,具體就是新增白名單和黑名單。

如何給請求指定流控應用,通過實現 RequestOriginParser 介面來完成,程式碼如下所示。

package com.southwind.configuration;

import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

public class RequestOriginParserDefinition implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        String name = httpServletRequest.getParameter("name");
        if(StringUtils.isEmpty(name)){
            throw new RuntimeException("name is null");
        }
        return name;
    }
}

要讓 RequestOriginParserDefinition 生效,需要在配置類中進行配置。

package com.southwind.configuration;

import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class SentinelConfiguration {

    @PostConstruct
    public void init(){
        WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
    }
}