9.Spring Cloud Alibaba Sentinel流控熔断组件

Sentinel

Sentinel 是面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。

GitHub:Sentinel

官网:Sentinel

Sentinel 功能和设计理念
  • 流量控制

    任意时间到来的请求往往是不可控的,而系统的处理能力是有限的。这就需要根据系统的能力对流量进行控制。

    流量控制有一下几个角度:

    • 资源的调用关系(资源的调用链路,资源与资源之间的关系等)
    • 运行指标(QPS、线程池、系统负载等)
    • 控制的效果(直接限流、冷启动、排队等)

    Sentinel的设计可以自由选择控制的角度,并进行灵活的组合,从而达到理想的效果。

  • 熔断降级

    Sentinel和Hystrix的原则是一致的:当调用链路中某个资源不稳定,则对这个资源的调用进行限制,并让请求快速失败,避免影响其他的资源,导致请求发生堆积,产生雪崩效应。

    在限制手段上,Hystrix通过线程池的方式,使资源和资源之间做到了彻底的隔离。缺点是增加了线程切换的成本,还需预先给各个资源做线程池大小分配。

    Sentinel对这个问题采取两种手段:

    • 通过并发数进行限制

      当线程数在特定资源上堆积到一定数量,对该资源的新请求会被拒绝,堆积的线程完成任务后才开始继续接收请求。

    • 通过响应时间对资源进行降级

      当依赖的资源响应时间过长,所有对该资源的访问都被直接拒绝,直到过了指定的时间窗口之后才恢复。

  • 系统负载保护

    当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载会把本应这台机器承载的流量转发到其他机器上,如果此时其他机器也处在一个边缘状态,增加的流量就会导致这台机器也崩溃,最终导致整个集群不可用。针对这个情况,Sentinel提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围内处理最多的请求。

Sentinel 的主要工作机制如下:

  • 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
  • Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。

关于更加详细的介绍,这里就不在介绍了,直接去官网查看官方文档,以及GitHub上面给的例子即可。

demo:sentinel-demo

文档:Sentinel用户文档

上手使用
  1. 准备工作

    上篇博客使用了Spring Cloud Alibaba Nacos作为服务注册中心,并在Idea中使用Alibaba Cloud Tookit插件创建项目。这里沿用昨天的book-service服务,再新建student-service服务,并使用OpenFeign调用book-service的服务。关于OpenFeign声明式服务调用在前面博客也讲解过,直接使用即可。引入OpenFeign依赖

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    先在book-service中编写demo

    在这里插入图片描述

    在student-service中编写demo,并使用OpenFeign调用book-service中的服务。这里要在启动类添加@EnableFeignClients

    在这里插入图片描述

    在Nacos中确认两个服务均已注册。

    在这里插入图片描述

    补充一下:这里为啥启动类中没有加@EnableDiscoveryClient?我们在查看生成的项目中,有一个nacosdiscovery包中有一个NacosDiscoveryConfiguration,该类中添加了@EnableDiscoveryClient注解

    在这里插入图片描述

    运行student-service调用book-service服务

    在这里插入图片描述

  2. 安装Sentinel Dashboard

    下载地址:Sentinel Dashboard

    下载完成以后,可以在本地运行。java -jar sentinel-dashboard-1.8.0.jar。启动以后发现Sentinel Dashboard的默认端口为8080,占用了别的端口,直接修改启动端口:java -jar -Dserver.port=8888 sentinel-dashboard-1.8.0.jar

    在这里插入图片描述

    直接访问ip+port 访问(用户名密码均为sentinel)

    在这里插入图片描述

    这里面暂时是没有服务列表的。需要在服务中进行配置登记。
    在这里插入图片描述

  3. 服务调用方(student-service)添加Sentinel依赖。完整核心pom.xml

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.4.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    
        <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>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    在配置文件中添加配置:

    spring:
      application:
        name: student-service
    
      cloud:
        nacos:
          discovery:
            username: nacos
            password: nacos
            server-addr: localhoost:8848
        sentinel:
          transport:
            dashboard: localhost:8888
    

    启动项目调用服务后,刷新Sentinel Dashboard页面。

    在这里插入图片描述

    我们可以在这里设置流控、降级。根据不同的情况设置。

    设置流控

    在这里插入图片描述

    设置降级

    在这里插入图片描述

    这里简单验证:设置流控

    在这里插入图片描述

    频繁刷新以后

    在这里插入图片描述

    补充:以student-service为例,微服务如何与Sentinel Dashboard通信?

    在微服务中引入Sentinel依赖以后,微服务中有一个sentinel-transport-simple-http客户端,该客户端默认在主机上开启一个新的端口(并不会使用微服务的端口),默认从8719开始,如果端口被占用,依次+1再次尝试。

    在这里插入图片描述

    sentinel-transport-simple-http客户端会获取微服务的状态等信息,进行健康检查(默认10秒向Sentinel Dashboard发送心跳包通知健康状态)。而如果我们在Sentinel Dashboard中设置了微服务的流控,降级,则Sentinel Dashboard会调用sentinel-transport-simple-http客户端中提供的API进行设置。

    从Sentinel Dashboard中我们看到微服务student-service中的sentinel-transport-simple-http端口为8720(8719已经被占用了)。我们直接访问ip + port + /api

    在这里插入图片描述
    在这里插入图片描述

  4. 上面的方法是在Sentinel Dashboard中设置流控,降级规则,我们也可以在代码中实现:

    流量规则

    Field说明默认值
    resource资源名,资源名是限流规则的作用对象
    count限流阈值
    grade限流阈值类型,QPS 或线程数模式QPS 模式
    limitApp流控针对的调用来源default,代表不区分调用来源
    strategy调用关系限流策略:直接、链路、关联根据资源本身(直接)
    controlBehavior流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流直接拒绝
    private void initFlowRule(){
    	List<FlowRule> rules = new ArrayList<>();
    	FlowRule rule = new FlowRule();
    	//设置资源名称
    	rule.setResource("/student/info/{stuNo}/{id}");
    	//设置限流阈值
    	rule.setCount(100);
    	//设置限流阈值类型
    	rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    	//设置策略
    	rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
    	//设置流控效果 设为预热
    	rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
    	//设置预热时间
    	rule.setWarmUpPeriodSec(10);
    	//设置调用来源
    	rule.setLimitApp("default");
    	rules.add(rule);
    	//定义流量控制规则
    	FlowRuleManager.loadRules(rules);
    }
    

    熔断降级规则

    Field说明默认值
    resource资源名,即规则的作用对象
    grade熔断策略,支持慢调用比例/异常比例/异常数策略慢调用比例
    count慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
    timeWindow熔断时长,单位为 s
    minRequestAmount熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)5
    statIntervalMs统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)1000 ms
    slowRatioThreshold慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
    private static void initDegradeRule() {
    	List<DegradeRule> rules = new ArrayList<>();
    	DegradeRule rule = new DegradeRule("/student/info/{stuNo}/{id}");
    	rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
    		.setCount(0.7)
    		.setMinRequestAmount(100)
    		.setStatIntervalMs(30000)
    		.setTimeWindow(10);
    	rules.add(rule);
    	DegradeRuleManager.loadRules(rules);
    }
    

    系统保护规则

    Field说明默认值
    highestSystemLoadload1 触发值,用于触发自适应控制阶段-1 (不生效)
    avgRt所有入口流量的平均响应时间-1 (不生效)
    maxThread入口流量的最大并发数-1 (不生效)
    qps所有入口资源的 QPS-1 (不生效)
    highestCpuUsage当前系统的 CPU 使用率(0.0-1.0)-1 (不生效)
    private void initSystemProtectionRule() {
      	List<SystemRule> rules = new ArrayList<>();
      	SystemRule rule = new SystemRule();
      	rule.setHighestSystemLoad(1.0);
      	rules.add(rule);
      	SystemRuleManager.loadRules(rules);
    }
    

    更多讲解,参见文档:基本使用 - 资源与规则

  5. Sentinel异常处理

    通过之前的测试,从页面返回的信息查看不够完整。

    在这里插入图片描述

    这里新建异常处理类,实现BlockExceptionHandler

    /**
     * 自定义Sentinel异常返回信息
     */
    @Component
    public class BlockHandler implements BlockExceptionHandler {
    
        @Override
        public void handle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse, BlockException e) throws Exception {
            String message = null;
            if(e instanceof FlowException){
                message = "请求已被限流!";
            }
            if(e instanceof DegradeException){
                message = "熔断!";
            }
            if(e instanceof ParamFlowException){
                message = "热点数据限流";
            }
            if(e instanceof SystemBlockException){
                message = "系统规则异常";
            }
            if(e instanceof AuthorityException){
                message = "授权规则异常";
            }
            httpServletResponse.setStatus(500);
            httpServletResponse.setCharacterEncoding("utf-8");
            httpServletResponse.setContentType("application/json");
            //使用ObjectMapper将对象转换成字符串
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            objectMapper.writeValue(httpServletResponse.getWriter(),new Result(500,message));
        }
    }
    

    补充:统一返回结果类

    public class Result<T> {
    
        private Integer code;
        private String message;
        private T data;
    
        public Result(){}
    
        public Result(T data){
            this.code = 200;
            this.message = "success";
            this.data = data;
        }
    
        public Result(Integer code, T data) {
            this.code = code;
            this.data = data;
        }
    
        public Result(Integer code, String message, T data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    

    设置限流规则以后再次尝试刷新

    在这里插入图片描述

  6. Sentinel与OpenFeign整合

    配置文件中新增配置

    feign:
      sentinel:
        enabled: true
    

    编写fallback回调方法
    在这里插入图片描述

    @FeignClient(name = "book-service",fallbackFactory = BookServiceFallback.class)
    public interface BookService {
    
        @GetMapping("/book/info/{id}")
        Result<Book> bookMessage(@PathVariable("id")String id);
    }
    

    回调
    在这里插入图片描述

    @Component
    public class BookServiceFallback implements FallbackFactory<BookService> {
    
        @Override
        public BookService create(Throwable throwable) {
            return new BookService() {
                @Override
                public Result<Book> bookMessage(String id) {
                    return new Result<>(500,throwable.getMessage(),null);
                }
            };
        }
    }
    

    划重点:

    • 回调方法实现FallbackFactory接口并添加对应的泛型。
    • 实现create方法,编写回调逻辑。
    • 添加@Component注解
  7. Sentinel在Nacos配置中心配置持久化

    在上述进行试验验证的过程中,会发现项目每次重启以后,设置的限流策略就失效了,需要重新设置。Nacos作为配置中心的讲解,后续在博客中更新。

    访问Nacos地址,在配置管理类-》配置列表中新建配置

    在这里插入图片描述

这里的值与规则列表中的值一致。
在这里插入图片描述

引入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

配置文件中新建配置

在这里插入图片描述

完整配置文件

server:
  port: 8050


spring:
  application:
    name: student-service

  cloud:
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848

    sentinel:
      transport:
        dashboard: localhost:8888

      datasource:
        flow-bs: #自定义名称
          nacos:
            server-addr: localhost:8848
            username: nacos
            password: nacos
            dataId: book-service-rule #data id
            groupId: DEFAULT_GROUP #分组
            ruleType: flow #flow代表流控规则,degrade代表熔断规则

feign:
  sentinel:
    enabled: true

同理配置熔断规则与限流规则一样操作即可(在Nacos中新建配置)。
在配置文件中新增配置:
在这里插入图片描述

验证:

重启项目,调用服务后,直接在Sentinel Dashboard流控规则中可看到。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值