天天看点

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/

创作不易感谢大家的观看!