2020SpringCloud学习年终总结——第十六章-Sentinel

Sentinel是阿里巴巴开源的分布式流量防卫兵,提供服务降级、熔断、限流等能力。本文详细介绍了Sentinel的安装、使用方法,包括如何设置流控规则、降级规则,以及通过Nacos实现规则持久化。此外,还探讨了Sentinel与Hystrix的对比优势。
摘要由CSDN通过智能技术生成

Sentinel前置

  • 官网:https://github.com/alibaba/Sentinel/wiki,分布式的流量防卫兵,轻量级的流量控制、断熔降级JAVA库;

在这里插入图片描述

  • How to use? https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

  • 粗略的说,可以应对服务使用中的以下问题:服务雪崩、服务降级、服务熔断、服务限流;

  • Sentinel组件由两部分组成,分别是后台,和前台8080;

    • 核心库(java客户端),不依赖任何框架和库,能够运行于所有java运行时的环境,同时对Dubbo,Spring Cloud等框架也有友好支持
    • 控制台(Dashboard),基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器;
  • 下载和安装:

    • 哪里下载:https://github.com/alibaba/Sentinel/releases
    • 运行:
      • 前提1:java8环境OK;
      • 前提2:8080端口不能被占用; 可以打开cmd,输入命令进行查看: netstat -aon|findstr “8080”
      • 到下载好的目录下,运行命令:java -jar sentinel-dashboard-1.7.0.jar
    • 访问sentinel管理界面:
      • http://localhost:8080
      • 账号密码均为:sentinel

版本说明

  • Sentinel 1.7.0

Sentinel初始化演示工程

  • 启动Nacos8848成功,这里我用上一章搭好的nacos集群,学以致用一下;

  • 创建Module;

    • cloudalibaba-sentinel-service8401

    • 修改POM,创建YML,

      • #application.yml
        server:
          port: 8401
        
        spring:
          application:
            name: cloudalibaba-sentinel-service
          cloud:
            nacos:
              discovery:
                #nacos集群服务注册中心地址
                server-addr: 192.168.56.128:1111
            sentinel:
              transport:
                #配置Sentinel dashboard地址
                dashboard: localhost:8080
                #默认8719端口,假如被占用,会自动从8719开始,依次+1扫描,直到找到未被占用的端口
                port: 8719
        
        management:
          endpoints:
            web:
              exposure:
                include: '*'
        
    • 主启动类,了解注解@EnableDiscoveryClient

    • controller:

      • package com.atguigu.springcloud.alibaba.controller;
        
        @RestController
        public class FlowLimitController {
            @GetMapping("/testA")
            public String testA(){
                return "---------testA";
            }
        
            @GetMapping("/testB")
            public String testB(){
                return "---------testB";
            }
        }
        
  • 启动Sentinel8080,java -jar sentinel-dashboard-1.7.0.jar;

  • 启动微服务8401,后台(localhost:8080),查看;

  • 发现后台什么都没有,这是因为sentinel采用的是懒得加载机制,需要执行一次访问后,才能看到效果,试着先访问:http://localhost:8401/testA或testB,再去后台查看,即可看到一个微服务的监控等功能列表;

Sentinel流控规则简介

在这里插入图片描述

  • 解释说明:
    • 资源名:唯一名称,默认是请求路径;
    • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名称,默认是default(不区分来源);
    • 阈值类型/单击阈值:
      • QPS(每秒请求数):当调用该api的QPS达到阈值,进行限流;
      • 线程数:当调用该api的线程数达到阈值时,进行限流;
    • 是否集群(sentinel集群):不需要集群;
    • 流控模式:
      • 直接:api达到限流条件时,直接限流;
      • 关联:当关联的资源达到阈值时,就限流自己;
      • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
    • 控流效果:
      • 快速失败:直接失败抛出异常;
      • Warm up:根据codeFactor(冷加载因子,默认是3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值;
      • 排队等待:匀速派对,让请求以匀速的速度通过,阈值类型必须设置未QPS,否则无效;

创建流控规则,可以从流控规则功能栏中添加,也可以到簇点链路中直接添加流控,一般是到簇点链路中;

  • 案例1:阈值类型——QPS直接失败

在这里插入图片描述

  • 注意资源名,即之前的localhost:8401不在范围内;

  • 这时的效果是,访问资源/testA,必须是一秒内只能有1个访问量,否则会在网页上报错:Blocked by Sentinel (flow limiting);

  • 这里报错时,直接调用的是默认的报错信息,技术方面是可以的,但是如何添加自己的后续处理呢?类似有一个fallback的兜底方法?

    • 有的,后面说;
  • 案例2:阈值类型——线程数直接失败

    • 线程数的意思是,每一次能处理的并发量,同一时间能处理的请求数;

    • 如何测试:可以设置线程数为1,然后在8401module中的controllelr中的/testA请求中,添加睡眠时间。然后访问/testA时狂点,报错Blocked by Sentinel (flow limiting);

      	@GetMapping("/testA")
          public String testA(){
              try {
                  TimeUnit.MILLISECONDS.sleep(800);
              }catch (InterruptedException e){
                  e.printStackTrace();
              }
              return "---------testA";
          }
      
  • 案例3:流控模式——关联

    • 当关联的资源达到阈值时,就限流自己;

    • 即当与A关联的资源B达到阈值后,就限流A自己;即在同一个的controller中的rest地址,例如testA和testB。B惹事,A挂了。

    • 应用:例如支付接口达到阈值时,就限流下订单的接口;

在这里插入图片描述

  • 当关联资源testB的QPS超过1时,限流testA;

  • 当关联资源到达阈值后,限流配置好的资源名;

  • 测试:

    • 用postman模拟并发密集的访问(20次迭代,间隔0.3秒执行一次访问)testB,然后观察/testA,报错;

在这里插入图片描述

  • 案例4:流控模式——链路

    • 只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
    • 解释:
      • 假设:请求接口/testA会调用service层的getOrder方法,/testB方法也会调用service层的getOrder方法;
        在这里插入图片描述

      • 此时如果/testA访问超过阈值,会进行流量控制;但/testB则不会。

  • 案例5:流控效果——预热

    • 根据codeFactor(冷加载因子,默认是3)的值,从(阈值/codeFactor),经过预热时长,才逐渐达到设置的QPS阈值;
    • 公式:阈值除以coldFactor(默认为3),经过预热时长后才会达到阈值;
    • 当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位,可能瞬间把系统压垮。通过“冷启动”,让流量缓慢增加,在一定时间逐渐增加到阈值上限;
      在这里插入图片描述
  • 案例6:流控效果——排队等待

    • 匀速排队,让请求以均匀的速度通过,阈值必须设置为QPS,否则无效;
    • 例如QPS阈值为1,则含义是/testA每秒请求1次,超过的话就排队等待,等待的超时时间自己设置;

Sentinel降级

在这里插入图片描述

  • 上述界面基本介绍

    • RT(平均响应时间,秒级):平均响应时间(例如1秒内进入5个请求),计算出平均响应时间。若超出阈值,且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级,窗口期过了之后关闭降级,RT最大4900(大概5秒内),更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
    • 异常比例(秒级):QPS>=5,且异常比例(秒级统计)超过阈值时,触发降级:时间窗口结束后,关闭降级;
    • 异常数(分钟级):异常数(分钟统计),超过阈值时,触发降级,时间窗口结束后,关闭降级;
  • Sentinel熔断降级会在调用链路中,某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

  • Sentinel的断路器是没有半开状态的。所谓半开状态,就是半开状态的系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器(不可用状态)。Sentinel是时间窗口到了,就关闭断路器恢复使用。

在这里插入图片描述

  • 案例1:Sentinel降级——RT

  • 案例2:Sentinel降级——异常比例

    • 异常比例:当资源的每秒请求量>=5,并且每秒异常总数占用通过量的比值超过阈值之后,资源进入降级状态。在接下来的时间窗口之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%~100%;

    • 在FlowLimitController下添加如下代码:

      	@GetMapping("/testF")
          public String testF(){
              log.info("testF 异常比例");
              int age = 10/0;
              return "---------testF";
          }
      
    • 开启JMETER后,直接高并发发送请求,多次调用达到熔断条件,服务降级。断路器开启(保险丝跳闸),微服务不可用了,不再报错error,而是服务降级了。

  • 案例3:Sentinel降级——异常数

    • 异常数:当资源近1分钟的异常数目超过阈值之后,会进行熔断。注意由于统计时间是分钟级别的,若timewindow小于60s,则结束熔断状态后仍可能再进入熔断状态。

Sentinel热点Key

  • 热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的Top K数据,并对其访问进行限制。

    • 例如:商品ID为参数,统计一段时间内最常购买的商品ID,并进行限制;用户ID为参数,针对一段时间内频繁访问的用户ID进行限制;
    • 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看作是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
  • 热点限流

    • 在controller中添加如下代码:
        @GetMapping("/testHotKey")
        @SentinelResource(value="testHotKey",blockHandler = "deal_testHotKey")//这里value是什么都行,这里只是为了好看
        public String testHotKey(@RequestParam(value="p1",required=false) String p1,
                                 @RequestParam(value="p2",required=false) String p2)
        {
            return "--------testHotKey";
        }
        
        public String deal_testHotKey(String p1, String p2, BlockException exception){
            return "--------deal_testHotKey,我是兜底备胎降级函数,错错错错错错";//代替系统默认提示:Blocked by Sentinel(flow limiting)
        }
    

在这里插入图片描述

  • 注意:这里资源名同代码中的value值,不带/。

  • 上面的单击阈值是QPS模式,所以是1秒一次的含义;参数索引0代表是第一个参数;

  • 上面的单击阈值是QPS模式,所以是1秒一次的含义;参数索引0代表是第一个参数;

  • 两种情况:

    • 普通:超过1秒种后,达到阈值1后马上被限流;
    • 特殊:我们期望p1参数当是某个特殊值时,它的限流值和平时不同;
  • 可以设置当参数p1为某个特定值时,其阈值也会变为特殊的值;

在这里插入图片描述

  • 注意:

    • @SentinelResource处理的时Sentinel的控制台配置的违规情况,有blockHandler方法配置的兜底处理;
    • 但是如果此时是代码出了问题(如10/0),则这个时java运行时产生的异常,不归@SentinelResource管。
    • 因此@SentinelResource主管配置出错,运行出错则该走异常就走异常。

Sentinel系统自适应限流

  • Sentinel系统自适应限流从整体维度对应用入口流量进行控制,结合应用的Load、CPU使用率、总体平均RT、入口QPS和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

  • 支持的模式:

    • Load自适应(仅对Linux/Unix-like机器生效):系统的load1作为启发指标,进行自适应系统的保护。当系统load1超过设定的启发值,且系统当前的并发线程数超过估值的系统容量时才会触发系统保护;
    • CPU usage:当系统CPU使用率超过阈值,即触发系统保护;
    • 平均RT:当单台机器所有入口流量的平均RT达到阈值,即触发系统保护,单位是毫秒;
    • 并发线程数:当单台机器所有入口流量的并发线程数达到阈值,即触发系统保护;
    • 入口QPS:当单台机器所有入口流量的QPS达到阈值,即触发系统保护。

在这里插入图片描述

  • 较为危险的方法

@SentinelResource的配置方法

  • 按资源名称限流+后续处理:

    • 启动nacos;启动sentinel;修改(cloudalibaba-sentinel-service8401),新写一个业务类RateLimitController

      @RestController
      public class RateLimitController {
          @GetMapping("/byResource")
          @SentinelResource(value = "byResource",blockHandler = "handlerException")
          public CommonResult byResource() {
              return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
          }
          
          public CommonResult handlerException(BlockException exception) {
              return new CommonResult(444,exception.getClass().getCanonicalName());
          }
      }
      
    • 对资源byResource设置流控,QPS阈值为1;

    • 关闭8401微服务后,流控规则也会跟着消失,因此是临时的。

  • 按照Url地址限流+后续处理

    • 通过访问URL来限流,会返回Sentinel自带默认的限流处理信息;

    • 往业务类RateLimitController添加相关代码;

      @GetMapping("/rateLimit/byUrl")
          @SentinelResource(value="byUrl")
          public CommonResult byUrl() {
              return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
          }
      
    • 访问一次;

    • Sentinel控制台配置,按照Url地址限流;

在这里插入图片描述

  • 测试;

  • 客户自定义限流处理逻辑

    • 上述用的,一般兜底方法面临的问题:

      • 系统默认的兜底方法,没有体现我们自己的业务要求;
      • 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观;
      • 每个业务方法都添加一个兜底的,会导致代码膨胀加剧;
      • 全局统一的处理方法没有体现;
    • 具体步骤:

      • 创建CustomerBlockHandler类,用于自定义限流处理逻辑;

        public class CustomerBlockHandler {
            public static CommonResult handlerException(BlockException exception){
                return new CommonResult(4444,"按照客户自定义的,global,的方法",new Payment(2020L,"serial003"));
            }
        }
        
      • 自定义限流处理类:CustomerBlockHandler;

      • 在RateLimitController中,添加如下代码;

        	@GetMapping("/rateLimit/customerBlockHandler")
            @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException")
            //即标明,哪个类中的哪个方法是兜底方法
            public CommonResult customerBlockHandler(){
                return new CommonResult(200,"按照客户自定义的兜底方法",new Payment(2020L,"serial003"));
            }
        
      • 启动微服务后先调用一次;

      • Sentinel控制台配置;

      • 测试自定义的兜底方法;

      • 进一步说明问题;

  • @SentinelResource的其他属性说明

    • Sentinel主要有三个核心API:
      • SphU定义资源;
      • Tracer定义统计;
      • ContextUtil定义上下文;

Sentinel熔断功能

  • sentinel整合了Ribbon(负载均衡)+openFeign( 远程调用)+fallback(降级);( OpenFeign是声明式、模板化的HTTP请求客户端。可以更加便捷、优雅地调用http api);

  • Ribbon系列:

    • 启动nacos和sentinel;

    • 提供者9003和9004;

      • 业务逻辑层代码:

        @RestController
        public class PaymentController {
        
            @Value("${server.port}")
            private  String serverPort;
        
            public static HashMap<Long, Payment > map = new HashMap<>();
            static {//这里当作一个dao层
                map.put(1L,new Payment(1L,"1111"));
                map.put(2L,new Payment(2L,"2222"));
                map.put(3L,new Payment(3L,"3333"));
            }
        
        
            @GetMapping(value = "/paymentSQL/{id}")
            public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
                Payment payment = map.get(id);
                CommonResult<Payment> result = new CommonResult<>(200,"from mysql,serverPort: " + serverPort,payment);
                return result;
            }
        }
        
    • 消费者84,经过ribbon负载均衡,调用9003和9004;

    • 注意:修改后请重启微服务,因为热部署对java代码级生效及时,对@SentinelResource注解内属性,有时效果不好;

    • 该实验目的,是为了对比fallback和blockHandler的区别:

      • fallback管运行异常;
      • blockHandler管配置违规;
      • 若blockHandler和fallback都进行了配置,则被限流降级而抛出BlockException时只会进入blockHandler处理逻辑;
    • 服务熔断exceptionsTolgnore,忽略已经在代码中抛出异常的情况;

  • Feign系列

    • 修改84模块:84消费者调用提供者9003,Feign组件一般用在消费侧;
    • 修改POM(添加OpenFeign)、YML(激活sentinel对feign的支持)、业务类、主启动(添加注解@EnableFeignClients)
    • 测试,访问http://localhost:84/consumer/paymentSQL/1
    • 测试84调用9003,此时故意关闭9003微服务提供者,看84消费侧自动降级;

sentinel规则的持久化

  • 之前说过,如果一个微服务被关闭了(或者重启),则sentinel中相关的配置也消失了,那么如何使配置规则持久化呢?

  • 我们可以将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里的配置不删除,针对8401上的sentinel上的流控规则持续有效;

  • 操作:

    • 修改8401的POM文件,添加sentinel-datasource-nacos定位,持久化需要用到;

    • 添加datasource配置

      server:
        port: 8401
      
      spring:
        application:
          name: cloudalibaba-sentinel-service
        cloud:
          nacos:
            discovery:
              #nacos集群服务注册中心地址
              server-addr: 192.168.56.130:1111
          sentinel:
            transport:
              #配置Sentinel dashboard地址
              dashboard: localhost:8080
              #默认8719端口,假如被占用,会自动从8719开始,依次+1扫描,直到找到未被占用的端口
              port: 8719
            datasource:
              ds1:
                nacos:
                  server-addr: 192.168.56.130:1111
                  dataId: cloudalibaba-sentinel-service #这是注册进sentinel的服务名称cloudalibaba-sentinel-service
                  groupId: DEFAULT_GROUP
                  data-type: json
                  rule-type: flow
      
      management:
        endpoints:
          web:
            exposure:
              include: '*'
      

在这里插入图片描述

* resource:资源名称
* limitApp:来源应用;
* grade:阈值类型,0表示线程数,1表示QPS
* count:单击阈值
* strategy:流控模式,0表示直接,1表示关联,2表示链路;
* controlBehavior:流控效果,0表示快速失败,1是warm up,2表示排队等待;
* clusterMode:是否集群;
  • 实现持久化;

知识点

tips

  • Hystrix不足:
  • 需要我们程序员自己手工搭建监控平台;
    • 没有一套web界面可以给我们进行更细粒度化的配置流控、速率控制、服务熔断、服务降级。。。。
  • Sentinel与上面Hystrix的对比:
    • 单独一个组件,可以独立出来;
    • 直接界面化的细粒度统一配置;
  • 约定>配置>编码;上面的流控、降级之列的都可以写在代码里,为了少些代码,可以用配置和注册;

代码地址:https://github.com/AJ-Spade/cloud2020/tree/master

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值