天天看點

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

一、Sentinel 描叙

1、Sentinel作用

Sentinel,中文翻譯為哨兵,是為微服務提供流量控制、熔斷降級的功能,它和Hystrix提供的功能一樣,可以有效的解決微服務調用産生的“雪崩”效應,為微服務系統提供了穩定性的解決方案。随着Hytrxi進入了維護期,不再提供新功能,Sentinel是一個不錯的替代方案。通常情況,Hystrix采用線程池對服務的調用進行隔離,Sentinel才用了使用者線程對接口進行隔離,二者相比,Hystrxi是服務級别的隔離,Sentinel提供了接口級别的隔離,Sentinel隔離級别更加精細,另外Sentinel直接使用使用者線程進行限制,相比Hystrix的線程池隔離,減少了線程切換的開銷。另外Sentinel的DashBoard提供了線上更改限流規則的配置,也更加的優化。

2、Sentinel 具有以下特征

從官方文檔的介紹,Sentinel 具有以下特征:

豐富的應用場景: Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷、實時熔斷下遊不可用應用等。

完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況。

廣泛的開源生态: Sentinel 提供開箱即用的與其它開源架構/庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。

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

3、如何在Spring Cloud中使用Sentinel

Sentinel的使用分為兩部分:

sentinel-dashboard:與hystrix-dashboard類似,但是它更為強大一些。除了與hystrix-dashboard一樣提供實時監控之外,還提供了流控規則、熔斷規則的線上維護等功能。

用戶端整合:每個微服務用戶端都需要整合sentinel的用戶端封裝與配置,才能将監控資訊上報給dashboard展示以及實時的更改限流或熔斷規則等。

4、Sentinel 和 hytrix的差別

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

二、Sentinel 控制台 Sentinel DashBoard

Sentinel DashBoard

Sentinel 控制台提供一個輕量級的控制台,它提供機器發現、單機資源實時監控、叢集資源彙總,以及規則管理的功能.

1、下載下傳

Sentinel DashBoard下載下傳位址:https://github.com/alibaba/Sentinel/releases

下載下傳 jar 檔案即可

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

2、啟動

下載下傳完成後,以以下的指令啟動

java -jar sentinel-dashboard-1.6.1.jar
           

啟動端口為8080,啟動修改端口添加指令 -Dserver.port=8081

3、通路

通路:http://localhost:8080

預設賬号密碼:sentinel / sentinel

登入成功展示如下,預設沒有任何内容的

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 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 分鐘;

三、springboot 整合 Sentinel

Sentinel 有兩種配置方式

1、使用代碼+注解配置(看7)

2、使用控制台配置(看6)

3.1、pom.xml 依賴

<!-- sentinel -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
           

3.2、application.yml

  • 在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
  • spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
  • spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。
##  在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
##  spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
##  spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。

server:
  port: 8090
spring:
  application:
    name: alibaba-alibaba-sentinel
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.177.128:8848
    ###  
    sentinel:
      transport:
        ### 目前項目Http Server ip,主要主要是和Sentinel  的DashBoard控制台系統進行通訊
        port: 8719
        ###  Sentinel 控制台DashBoard的位址
        dashboard: http://localhost:8080


           

3.4、測試接口1(指定方法,不介意,代碼都在一個地方)

關于@SentinelResource注解最主要的兩個用法:限流控制和熔斷降級的具體使用案例介紹完了。另外,該注解還有一些其他更精細化的配置,比如忽略某些異常的配置、預設降級函數等等

package com.example.alibabasentinel.service;


import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * TODO  服務熔斷/限流/降級(指定方法)
 * @author 王松
 * @mail  [email protected]
 * @date  2020/1/22 0022 20:35
 */
@RestController
public class TestService1Impl {

    /**
     * TODO   測試方法(目前類處理-服務降級)
     *  getName :限流名稱,控制台添加一定要選擇該值,勿添加為 /getName 預設名,否則exceptionHandler  參數無效
     *  exceptionHandler : 服務限流降級後執行的方法
     */
    @GetMapping("/getName")
    @SentinelResource(value = "getName", blockHandler = "exceptionHandler")
    public String getName() {
        return "wangsong";
    }

    /**
     * TODO   處理限流與阻塞(服務降級傳回友好提示),方法名對應 blockHandler的參數,服務限流降級後執行的方法
     * 
     */
    public String exceptionHandler(BlockException ex) {
        System.out.println("====" + ex);
        return "目前通路人數過多,請稍後再試";
    }
}

           

參考傳回值:

1、目前通路人數過多,請稍後再試

2、正在排隊中…

3.5、測試接口2(指定Handler類的方法)

添加測試方法

package com.example.alibabasentinel.service;


import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.example.alibabasentinel.handler.MyBlockHandlerClass;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
  * TODO   服務熔斷/限流/降級(指定Handler類的方法)
  * @author 王松
  * @mail  [email protected]
  * @date  2020/1/22 0022 20:40 
  */
@RestController
public class TestService2Impl {

    /**
     * TODO    測試方法(指定Handler類處理-服務降級),blockHandlerClass = MyBlockHandlerClass.class
     *  getName :限流名稱,控制台添加一定要選擇該值,勿添加為 /getName2 預設名,否則exceptionHandler  參數無效
     *  blockHandlerClass :服務限流/異常等指定類執行降級方法
     *  blockHandler: 服務限流執行的降級方法
     *  fallback :  服務異常執行的降級方法
     */
    @GetMapping("/getName2")
    @SentinelResource(value = "getName2", blockHandlerClass = MyBlockHandlerClass.class, blockHandler = "blockHandlerFunc", fallback = "fallbackFunc")
    public String getName2(String a) {
        return "wangsong2";
    }
}

           

添加 MyBlockHandlerClass 類 處理服務熔斷降級

import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyBlockHandlerClass {

    // 處理限流與阻塞(服務降級傳回友好提示)
    public static String blockHandlerFunc(String a, BlockException e){
        log.warn("限流了==="+a,e);
        return "目前通路人數過多,請稍後再試";
    }


    // 服務異常(降級處理)
    public static String fallbackFunc(String a){
        log.warn("異常==="+a);
        return "";
    }
}
           

3.6、控制台添加流控并測試

qbs:門檻值 = 每秒能調用該接口多少次

線程數:門檻值 = 請求最多有多少個線程池來處理(預設1)

項目啟動後等一下下,控制台在會出現目前服務資訊

先通路接口 /getName 幾次,控制台才會出現該接口資訊,

3.6.1、添加流控(接口到達門檻值自動熔斷)

getName = @SentinelResource注解的value 值,如果流控添加到 /getName ,将無法使用服務降級功能

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

添加流控qbs,設定門檻值為2

qbs:門檻值 = 每秒能調用該接口多少次

線程數:門檻值 = 請求最多有多少個線程池來處理(預設1)

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

3.6.2、通路接口(服務降級)

正常通路接口傳回響應資料,如目前:wangsong

到達門檻值上限 ,傳回:Blocked by Sentinel (flow limiting)

設定 blockHandle, 到達門檻值上限,傳回如下:

如:@SentinelResource(value=“getName”, blockHandler = “exceptionHandler”),

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

四、@SentinelResource 注解說明

注解key 支援版本 注解value 說明
value 資源名稱,必需項(不能為空)
entryType entry 類型,可選項(預設為 EntryType.OUT)
blockHandler / blockHandlerClass blockHandler對應處理 BlockException 的函數名稱,可選項。blockHandler 函數通路範圍需要是public,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為 BlockException。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 blockHandlerClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析
fallback 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 邏輯中,而是會原樣抛出。

五、java 代碼手動添加流控配置

pom 依賴,yml配置,看 3.1, 3.2

定義限流的接口添加注解看 3.4, 3.5

測試看 3.6

// 流控接口
private static final String GETORDER_KEY = "getOrder";

// 調用接口方式添加流控
@RequestMapping("/initFlowQpsRule")
public String initFlowQpsRule() {

    List<FlowRule> rules = new ArrayList<FlowRule>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource(GETORDER_KEY);
    // 設定QPS控制在2以内
    rule1.setCount(1);
    // 限流規則QPS
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    // 添加流控集
    FlowRuleManager.loadRules(rules);
    return "....限流配置初始化成功..";
}
           

六、Sentinel 資料持久化

1、pom.xml 依賴添加sentinel-datasource-nacos

<!-- sentinel ,可需啟動dashboard 檢視配置 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>
        <!-- sentinel 資料持久化到nacos  -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>1.5.2</version>
        </dependency>
           

2、nacos 添加 sentinel 配置

建立服務對應的 sentinel 配置檔案,使用 json

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

選擇json,添加資料

[
    {
        "resource": "/hello",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
           
  • resource:資源名,即限流規則的作用對象
  • limitApp:流控針對的調用來源,若為 default 則不區分調用來源
  • grade:限流門檻值類型(QPS 或并發線程數);0代表根據并發數量來限流,1代表根據QPS來進行流量控制
  • count:限流門檻值
  • strategy:調用關系限流政策
  • controlBehavior:流量控制效果(直接拒絕、Warm Up、勻速排隊)
  • clusterMode:是否為叢集模式

    這裡我們隻做簡單的配置解釋,以便于了解這裡的配置作用。實際上這裡還有非常多可配置選項和規則,更複雜的配置後面我們單獨開一篇來深入學習。

3、application.yml 完整配置

#  在工程的配置檔案application.yml檔案中配置,需要新增2個配置:
#  spring.cloud.sentinel.transport.port: 8719 ,這個端口配置會在應用對應的機器上啟動一個 Http Server,該 Server 會與 Sentinel 控制台做互動。比如 Sentinel 控制台添加了1個限流規則,會把規則資料 push 給這個 Http Server 接收,Http Server 再将規則注冊到 Sentinel 中。
#  spring.cloud.sentinel.transport.dashboard: 8080,這個是Sentinel DashBoard的位址。
server:
  port: 8090
spring:
  application:
    name: spring-cloud-alibaba-sentinel
  cloud:
    ### nacos 注冊中心
    nacos:
      discovery:
        server-addr: 192.168.177.132:8848
    sentinel:
      ### 和 Sentinel控制台DashBoard通訊,|| port:目前項目Http Server ip位址,|| dashboard:Sentinel 控制台DashBoard的位址
      transport:
        port: 8719
        dashboard: http://localhost:8080
      ### 配置資料源,支援file本地,nacos,zk,阿波羅,配置資料庫0,讀取 nacos 配置資料
      datasource:
        ds0:
          nacos:
            server-addr: 192.168.177.132:8848
            dataId: spring-cloud-alibaba-sentinel.json
            groupId: DEFAULT_GROUP
            rule-type: flow  
            ### 檔案類型    
            data-type: json     
           

sentinel 部分

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: http://localhost:8080
      datasource:
        ds0:
          nacos:
            server-addr: 192.168.177.132:8848
            dataId: spring-cloud-alibaba-sentinel.json
            groupId: DEFAULT_GROUP
            rule-type: flow
            data-type: json
           

4、檢視是否配置成功

啟動項目發現啟動日志: [Sentinel Starter] DataSource ds0-sentinel-nacos-datasource load 1 FlowRule

表示配置成功了

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

進入Sentinel 控制台–> 流控規則,發現已經存在配置規則了,配置成功

  • 1、如是重新啟動項目, 通路任意接口在等待幾秒重新整理
  • 2、配置了nacos 盡量從來nacos 添加和修改規則,Sentinel 控制台修改的下次重新啟動項目将失效
    SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

七、gateway 整合 Sentinel 實作服務限流

1、添加sentinel 限流核心配置

package com.gateway.sentinel;

import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;

import java.util.Collections;
import java.util.List;
/**
  * TODO  sentinel 限流核心配置
  * @author ws
  * @mail  [email protected]
  * @date  2020/2/17 0017 14:08
  */
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }


}
           

2、添加sentinel 限流規則

此配置可以配置到nacos,動态配置限流規則

package com.gateway.sentinel;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * TODO  限流規則配置
 *
 * @author ws
 * @mail [email protected]
 * @date 2020/2/17 0017 14:09
 */
@Slf4j
@Component
public class SentinelApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        initGatewayRules();

    }

    /**
     * 配置限流規則
     */
    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("test")
                // 限流門檻值
                .setCount(1)
                // 統計時間視窗,機關是秒,預設是 1 秒
                .setIntervalSec(1)
        );
        GatewayRuleManager.loadRules(rules);
    }
}

           

3、配置自定義傳回資訊(如果配置了全局異常看四)

package com.gateway.sentinel;

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;
/**
  * TODO  限流錯誤傳回資訊
  * @author ws
  * @mail  [email protected]
  * @date  2020/2/17 0017 14:13
  */
public class JsonSentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
    public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
        serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        byte[] datas = "{\"code\":403,\"msg\":\"API接口被限流\"}".getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
        return serverHttpResponse.writeWith(Mono.just(buffer));
    }

}




           

4、全局異常傳回自定義資訊

全局異常配置暫不做說明

SpringCloudAlibaba 六、Sentinel 服務保護 ( 服務降級/ 熔斷/ 資料持久化 / gateway 整合 Sentinel )

本文參考文章1:https://blog.csdn.net/u013184307/article/details/95973022

本文參考文章2:https://blog.csdn.net/a772304419/article/details/99689562

資料持久化參考:http://blog.didispace.com/spring-cloud-alibaba-sentinel-2-1/

創作不易感謝大家的觀看!