• (三)SpringCloudAlibaba熔断与限流-Sentinel


    1.Sentinel简介

    官网:https://github.com/alibaba/Sentinel

    下载:https://github.com/alibaba/Sentinel/releases

    Sentinel 具有以下特征:

    • 丰富的应用场景 :Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
    • 完备的实时监控 :Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
    • 广泛的开源生态 :Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 SpringCloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
    • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

    Sentinel 的主要特性:

    Sentinel 与Hystrix的区别

    Sentinel 官方提供了详细的由Hystrix 迁移到Sentinel 的方法
    https://github.com/alibaba/Sentinel/wiki/Guideline:-从-Hystrix-迁移到-Sentinel

    名词解释
    Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合Dashboard 可以取得最好的效果。
    使用 Sentinel 来进行熔断保护,主要分为几个步骤:

    1. 定义资源
    2. 定义规则
    3. 检验规则是否生效

    资源:可以是任何东西,一个服务,服务里的方法,甚至是一段代码。
    规则:Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和 热点参数规则。Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效
    先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何
    时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保
    护,就将之定义为一个资源。

    2.安装Sentinel控制台

    2.1sentinel组件由2部分构成

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

    2.2安装步骤

    • https://github.com/alibaba/Sentinel/releases
    • 下载到本地sentinel-dashboard-1.7.0.jar
    • java8环境ok 8080端口不能被占用
    • 命令 java -jar sentinel-dashboard-1.7.0.jar
    • 访问http://localhost:8080 登陆账号密码均为sentinel

    3.初始化演示工程

    3.1启动Nacos8848成功

    http://localhost:8848/nacos/#/login

    3.2新建工程

    • 工程
    cloud-alibaba-sentinel-service-8401
    
    • pom
            <!--SpringCloud ailibaba nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
            </dependency>
            <!--SpringCloud ailibaba sentinel -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
    
    • yml
    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            #Nacos服务注册中心地址
            server-addr: localhost:8848
        sentinel:
          transport:
            #配置Sentinel dashboard地址
            dashboard: localhost:8080
            #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
            port: 8719
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
    • 主启动类
    @EnableDiscoveryClient
    @SpringBootApplication
    public class SentinelServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SentinelServiceApplication.class, args);
        }
    }
    
    • Controller
    @RestController
    public class FlowLimitController
    {
    
        @GetMapping("/testA")
        public String testA()
        {
            return "------testA";
        }
    
        @GetMapping("/testB")
        public String testB()
        {
            return "------testB";
        }
    }
    

    3.流控规则

    3.1基本介绍


    进一步说明

    3.2流控模式

    3.2.1直接(默认)
    • 直接->快速失败(系统默认)
    • 配置及说明
    • 测试 快速点击访问 http://localhost:8401/testA
    • 结果 Blocked by Sentinel(flow limiting)
    • 思考 直接调用默认报错信息,技术方面OK,但是是否应该有我们自己的后续处理(类似有个fallback的兜底方法)
    3.2.2关联
    • 是什么?
      当关联的资源到达阈值时,就限流自己
      当与A关联的资源B到达阈值后,就限流A自己
      B惹事,A挂了
    • 配置A
    • postman模拟并发密集访问testB

      访问testB成功

      postman里新建多线程及合组

      将访问地址添加新线程组
    • Run
      大批量线程高并发访问B,导致A失效
    • 点击访问http://localhost:8401/testA 结果 Blocked by Sentinel(flow limiting)
    3.2.3链路

    多个请求调用了同一个微服务

    3.3流控效果

    3.3.1直接->快速失败(默认的流控处理)

    Blocked by Sentinel(flow limiting)
    源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

    3.3.2预热

    公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

    默认coldFactor为3,即请求QPS从threshold/3 开始,经预热时长逐渐升至设定的QPS阈值
    源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

    • WarmUp配置

    • 测试 多次点击http://localhost:8401/testB 刚开始不行,后续慢慢OK

    • 应用场景
      如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。

    3.3.3排队等待

    匀速排队,阈值必须设置为QPS

    源码:com.alibaba.csp.sentinel,slots.block.flow.controller.RateLimiterController

    4.降级规则

    4.1基本介绍


    RT(平均响应时间,秒级)
    平均响应时间 超出阈值 且 在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
    窗口期过后关闭断路器
    RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
    异常比列(秒级)
    QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
    异常数(分钟级)
    异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

    4.2进一步说明

    Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

    4.3Sentinel得断路器是没有半开状态的

    半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用,具体可以参考Hystrix

    4.4降级策略实战

    4.4.1 RT是什么?

    测试

    • 代码
    @GetMapping("/testD")
    public String testD()
    {
        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        log.info("testD 测试RT");
        return "------testD";
    }
      
    
    • 配置
    • jmeter压测
    • 结论

      按照上述配置永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK。
    4.4.2异常比例

    测试

    • 代码
    @GetMapping("/testD")
    public String testD()
    {
        log.info("testD 测试RT");
        int age = 10/0;
        return "------testD";
    }
    
    • 配置
    • jmeter
    • 结论
      按照上述配置,单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次;

      开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。
    4.4.3异常数

    • 异常数是按分钟统计的
      测试
    • 代码
    @GetMapping("/testE")
    public String testE()
    {
        log.info("testE 测试异常比例");
        int age = 10/0;
        return "------testE 测试异常比例";
    }
    

    5.热点key限流

    5.1基本介绍

    何为热点
    热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

    5.2从HystrixCommand 到@SentinelResource

    之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?
    从HystrixCommand 到@SentinelResource

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1, 
                             @RequestParam(value = "p2",required = false) String p2){
        return "------testHotKey";
    }
    public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
    {
        return "-----dealHandler_testHotKey";
    }
    

    配置

    限流模式只支持QPS模式,固定写死了。(这才叫热点)
    @SentinelResource注解的方法参数索引,0代表第一个参数,1代表第二个参数,以此类推
    单机阀值以及统计窗口时长表示在此窗口时间超过阀值就限流。
    上面的抓图就是第一个参数有值的话,1秒的QPS为1,超过就限流,限流后调用dealHandler_testHotKey支持方法。

    测试

    5.3参数例外项

    上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
    特殊情况
    普通:超过1秒钟一个后,达到阈值1后马上被限流
    我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
    特例:假如当p1的值等于5时,它的阈值可以达到200

    配置

    测试

    当p1等于5的时候,阈值变为200,当p1不等于5的时候,阈值就是平常的1
    热点参数注意点,参数必须是基本类型或者String

    6.系统规则

    7.@SentinelResource

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

    • 启动Nacos
    • 启动Sentinel
    • cloud-alibaba-sentinel-service-8401 添加RateLimitController
    @RestController
    public class RateLimitController
    {
        @GetMapping("/byResource")
        @SentinelResource(value = "byResource",blockHandler = "handleException")
        public CommonResult byResource()
        {
            return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
        }
        public CommonResult handleException(BlockException exception)
        {
            return new CommonResult(444,exception.getClass().getCanonicalName()+"	 服务不可用");
        }
    }
    
    • 配置流控规则
      配置步骤

      图形配置和代码关系

      表示1秒钟内查询次数大于1,就跑到我们自定义的处理,限流
    • 测试
      1秒钟点击1下OK
      疯狂点击,返回了自定义的限流处理信息,限流发生
    • 额外问题
      此时关闭服务8401看看
      Sentinel控制台,流控规则消失了

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

    • 通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息
    • 业务类RateLimitController
    @RestController
    public class RateLimitController
    {
        @GetMapping("/byResource")
        @SentinelResource(value = "byResource",blockHandler = "handleException")
        public CommonResult byResource()
        {
            return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
        }
        public CommonResult handleException(BlockException exception)
        {
            return new CommonResult(444,exception.getClass().getCanonicalName()+"	 服务不可用");
        }
    
        @GetMapping("/rateLimit/byUrl")
        @SentinelResource(value = "byUrl")
        public CommonResult byUrl()
        {
            return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
        }
    }
    

    7.3上面兜底方案面临的问题

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

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

    • 创建CustomerBlockHandler类用于自定义限流处理逻辑
    public class CustomerBlockHandler
    {
        public static CommonResult handleException(BlockException exception){
            return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
        }
    }
    
    • RateLimitController
        /**
         * 自定义通用的限流处理逻辑
         */
        @GetMapping("/rateLimit/customerBlockHandler")
        @SentinelResource(value = "customerBlockHandler",
                blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
        public CommonResult customerBlockHandler()
        {
            return new CommonResult(200,"按客户自定义限流处理逻辑");
        }
    

    7.5@SentinelResource更多注解说明



    注:1.6.0 之前的版本 fallback 函数只针对降级异常( DegradeException )进行处理,不能针对业务异常进行处理。

    特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler 、 fallback 和 defaultFallback ,则被限流降级时会将 BlockException 直接抛出。

    8.服务熔断功能

    Sentinel整合ribbon+openFeign+fallback

    8.1Ribbon系列

    • 服务提供者9003/9004
    cloud-alibaba-provider-payment-9003
    cloud-alibaba-provider-payment-9004
    
    • pom
            <!--SpringCloud ailibaba nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    
    • yml 记得修改不同的端口
    server:
      port: 9003
    
    spring:
      application:
        name: nacos-payment-provider
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #配置Nacos地址
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
    • 主启动类
    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentApplication9003 {
    
        public static void main(String[] args) {
            SpringApplication.run(PaymentApplication9003.class, args);
        }
    
    }
    
    • 业务类Controller
    @RestController
    public class PaymentController {
    
        @Value("${server.port}")
        private String serverPort;
    
        public static HashMap<Long, Payment> hashMap = new HashMap<>();
    
        static {
            hashMap.put(1L, new Payment(1L, "28a8c1e3bc2742d8848569891fb42181"));
            hashMap.put(2L, new Payment(2L, "bba8c1e3bc2742d8848569891ac32182"));
            hashMap.put(3L, new Payment(3L, "6ua8c1e3bc2742d8848569891xt92183"));
        }
    
        @GetMapping(value = "/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
            Payment payment = hashMap.get(id);
            CommonResult<Payment> result = new CommonResult(200, "from mysql,serverPort:  " + serverPort, payment);
            return result;
        }
    
    }
    
    cloud-alibaba-consumer-order-84
    
    • pom
            <!--SpringCloud ailibaba nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!--SpringCloud ailibaba sentinel -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
    
    • yml
    server:
      port: 84
    
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          transport:
            #配置Sentinel dashboard地址
            dashboard: localhost:8080
            #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
            port: 8719
    
    
    #消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
    service-url:
      nacos-user-service: http://nacos-payment-provider
    
    • 主启动类
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class OrderApplication84 {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication84.class, args);
        }
    }
    
    • 配置Bean
    @Configuration
    public class ApplicationContextConfig
    {
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    }
    
    @RestController
    @Slf4j
    public class CircleBreakerController
    {
        public static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
        @SentinelResource(value = "fallback") 
         public CommonResult<Payment> fallback(@PathVariable Long id)
        {
            CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
    
            if (id == 4) {
                throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
            }else if (result.getData() == null) {
                throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
            }
    
            return result;
        }
    }
    

    只配置fallback

    @RestController
    @Slf4j
    public class CircleBreakerController
    {
        public static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
        @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback负责业务异常
        public CommonResult<Payment> fallback(@PathVariable Long id)
        {
            CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
    
            if (id == 4) {
                throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
            }else if (result.getData() == null) {
                throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
            }
    
            return result;
        }
        public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
        }
    }
    


    结果

    只配置blockHandler

    @RestController
    @Slf4j
    public class CircleBreakerController
    {
        public static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
         @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler负责在sentinel里面配置的降级限流
        public CommonResult<Payment> fallback(@PathVariable Long id)
        {
            CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
            if (id == 4) {
                throw new IllegalArgumentException ("非法参数异常....");
            }else if (result.getData() == null) {
                throw new NullPointerException ("NullPointerException,该ID没有对应记录");
            }
            return result;
        }
        public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
        }
        public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
        }
    
    }
    


    结果

    fallback和blockHandler都配置

    @RestController
    @Slf4j
    public class CircleBreakerController
    {
        public static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
         @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
        public CommonResult<Payment> fallback(@PathVariable Long id)
        {
            CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
            if (id == 4) {
                throw new IllegalArgumentException ("非法参数异常....");
            }else if (result.getData() == null) {
                throw new NullPointerException ("NullPointerException,该ID没有对应记录");
            }
            return result;
        }
        public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
        }
        public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
        }
    
    }
    

    结果

    若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。

    忽略属性

    @RestController
    @Slf4j
    public class CircleBreakerController
    {
        public static final String SERVICE_URL = "http://nacos-payment-provider";
    
        @Resource
        private RestTemplate restTemplate;
    
        @RequestMapping("/consumer/fallback/{id}")
        @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
                exceptionsToIgnore = {IllegalArgumentException.class})
        public CommonResult<Payment> fallback(@PathVariable Long id)
        {
            CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
            if (id == 4) {
                throw new IllegalArgumentException ("非法参数异常....");
            }else if (result.getData() == null) {
                throw new NullPointerException ("NullPointerException,该ID没有对应记录");
            }
            return result;
        }
        public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(444,"fallback,无此流水,exception  "+e.getMessage(),payment);
        }
        public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
            Payment payment = new Payment(id,"null");
            return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
        }
    }
    


    结果

    8.2Feign系列

    • 修改84模块
      84消费者调用提供者9003Feign组件一般是消费侧
    • pom
            <!--SpringCloud openfeign -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    
    • yml 激活Sentinel对Feign的支持
    server:
      port: 84
    
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            #Nacos服务注册中心地址
            server-addr: localhost:8848
        sentinel:
          transport:
            #配置Sentinel dashboard地址
            dashboard: localhost:8080
            #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
            port: 8719
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    # 激活Sentinel对Feign的支持
    feign:
      sentinel:
        enabled: true  
    
    • 业务类PaymentService
    /**
     * 使用 fallback 方式是无法获取异常信息的,
     * 如果想要获取异常信息,可以使用 fallbackFactory参数
     */
    @FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
    public interface PaymentService
    {
        @GetMapping(value = "/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
    }
    
    • fallback=PaymentFallbackService.class
    @Component
    public class PaymentFallbackService implements PaymentService
    {
        @Override
        public CommonResult<Payment> paymentSQL(Long id)
        {
            return new CommonResult<>(444,"服务降级返回,没有该流水信息",new Payment(id, "errorSerial......"));
        }
    }
    
    • Controller
        //==================OpenFeign
        @Resource
        private PaymentService paymentService;
    
        @GetMapping(value = "/consumer/openfeign/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
        {
            if(id == 4)
            {
                throw new RuntimeException("没有该id");
            }
            return paymentService.paymentSQL(id);
        }
    
    • 主启动类 添加@EnableFeignClients启动Feign的功能
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class OrderNacosMain84
    {
        public static void main(String[] args) {
                SpringApplication.run(OrderNacosMain84.class, args);
        }
    }
    

    9.规则持久化

    9.1是什么?

    一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

    9.2怎么玩?

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

    9.3步骤

    • 修改cloud-alibaba-sentinel-service-8401
    • pom
    <!--SpringCloud ailibaba sentinel-datasource-nacos -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    
    • yml 添加Nacos数据源配置
    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #Nacos服务注册中心地址
        sentinel:
          transport:
            dashboard: localhost:8080 #配置Sentinel dashboard地址
            port: 8719
          datasource:
            ds1:
              nacos:
                server-addr: localhost:8848
                dataId: cloudalibaba-sentinel-service
                groupId: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
    feign:
      sentinel:
        enabled: true # 激活Sentinel对Feign的支持
    
    • 添加Nacos业务规则配置

    • 内容解析

     
    [
        {
            "resource": "/rateLimit/byUrl",
            "limitApp": "default",
            "grade": 1,
            "count": 1,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        }
    ]
    
    resource:资源名称;
    limitApp:来源应用;
    grade:阈值类型,0表示线程数,1表示QPS;
    count:单机阈值;
    strategy:流控模式,0表示直接,1表示关联,2表示链路;
    controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
    clusterMode:是否集群。
    
  • 相关阅读:
    Verilog杂谈
    Hadoop家族学习路线图
    R语言中apply函数
    R语言数组array函数
    R语言列表list函数
    R语言多元素向量
    R语言提取字符串的一部分substring函数
    R语言改变大小写 toupper()和 tolower()函数
    R语言统计字符串的字符数ncahr函数
    R语言格式化数字和字符串format函数
  • 原文地址:https://www.cnblogs.com/everyingo/p/14784610.html
Copyright © 2020-2023  润新知