微服务之服务限流和熔断Sentinel

B站尚硅谷P111~P137
代码Gitee地址

1. sentinel

分布式系统的流量防卫兵。
以流量为切入点,从流量控制、熔断降级、系统负载保护等多个纬度保护服务的稳定性。

1.1 特征

  • 丰富的应用场景:秒杀、消息削峰填谷、集群流量控制、事实熔断下游不可应用等。
  • 完备的实时监控:可以在控制台中看到接入应用的单台机器秒级数据。
  • 广泛的开源生态:提供开箱即用的与其他开源框架/库的整合,与Spring Cloud、Dubbo、等,只需要接入相应依赖并简单的配置就可以;
  • 完善的SPI扩展点:可以通过扩展接口来快速的定制逻辑。

微服务之服务限流和熔断Sentinel_第1张图片

  • 作用:
    1. 防止服务雪崩;
    2. 服务降级;
    3. 服务熔断;
    4. 服务限流。

1.2 安装

  • 下载地址:https://github.com/alibaba/Sentinel/releases
    微服务之服务限流和熔断Sentinel_第2张图片
  • 下载之后,直接使用java -jar运行jar包即可,但是要保证8080端口不能被占用。
    默认用户名和密码都是sentinel。
    微服务之服务限流和熔断Sentinel_第3张图片

1.3 微服务搭建

  • 新建moudule:cloudalibaba-sentinel-service8401

  • 依赖:

        <dependencies>
        
    		<dependency>
            	<groupId>org.examplegroupId>
            	<artifactId>cloud-api-commonsartifactId>
            	<version>1.0-SNAPSHOTversion>
        	dependency>
        	
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
            <dependency>
                <groupId>com.alibaba.cspgroupId>
                <artifactId>sentinel-datasource-nacosartifactId>
            dependency>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
    
            <dependency>
                <groupId>cn.hutoolgroupId>
                <artifactId>hutool-allartifactId>
                <version>4.6.3version>
            dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
        dependencies>
    
  • 配置文件:

    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
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
  • 启动类:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class SentinelMain8401 {
        public static void main(String[] args) {
            SpringApplication.run(SentinelMain8401.class,args);
        }
    }
    
  • controller:

    @Slf4j
    @RestController
    public class FlowLimitController {
        
        @GetMapping("/testA")
        public String testA() {
            return "------testA";
        }
    
        @GetMapping("/testB")
        public String testB() {
            return "------testB";
        }
    
    }
    
  • 启动之后,由于sentinel是懒加载机制,必须执行一次当前微服务的访问:http://localhost:8401/testA,才可以看到:
    微服务之服务限流和熔断Sentinel_第4张图片

1.4 流量控制

1.4.1 QPS——直接快速失败

QPS:达到设置的每秒请求数,进行限流;直接:api达到限流条件时,直接限流;快速失败:直接抛出异常。

  • /testA新增如下流控规则:
    微服务之服务限流和熔断Sentinel_第5张图片
  • 连续请求两次接口:直接被拦截
    微服务之服务限流和熔断Sentinel_第6张图片

1.4.2 线程数——直接失败

线程数:当调用该API的线程数达到阈值时,进行限流;直接:api达到限流条件时,直接限流。
即针对一个请求设置对应数量的线程进行处理,如果当前线程来不及处理请求时才会抛出异常。

微服务之服务限流和熔断Sentinel_第7张图片

1.4.3 关联

关联:当关联的资源达到阈值时,限流自己。

例如,这里如果/testB超过设置的阈值,就会对/testA进行访问限制。
微服务之服务限流和熔断Sentinel_第8张图片

1.4.4 预热(Warm up)

预热方式,当系统长期处于低水位的情况,当流量突然激增时,直接把系统拉升到高水位可能瞬间把系统压垮。
通过冷启动,让通过的流量缓慢增加,在一定时间内增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

默认的冷加载因子是3,在设定的预热时长内最多承受阈值10/3的QPS,当超过预热时长(5秒)后可以达到最大阈值。
微服务之服务限流和熔断Sentinel_第9张图片

1.4.4 排队等待

匀速排队,让请求以均匀的速度通过,阈值只能是QPS类型。
主要用于处理间歇性突发的流量。

如果超过当前设置的阈值(1),则等待20000毫秒。

微服务之服务限流和熔断Sentinel_第10张图片

1.4 熔断降级

熔断降级会在调用链路中某个资源出现部稳定时,对资源的调用进行限制,让请求快速失败,避免影响到其它资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都自动熔断。

  • 降级规则:
    1. RT(秒级):平均响应时间,只有时间窗口内通过的请求大于等于5且超出阈值同时触发,才会触发降级。
    2. 异常比例(秒级):QPS>= 5超过阈值时,触发降级,时间窗口结束后,关闭降级。
    3. 异常数(分支级):当异常数超过于阈值时,触发降级,时间窗口结束后,关闭降级。

不存在半开状态,只有开和关。

微服务之服务限流和熔断Sentinel_第11张图片

1.4.1 RT

  • 断开方式:
    微服务之服务限流和熔断Sentinel_第12张图片

  • 修改代码:这里让/testB睡2秒。

        @GetMapping("/testB")
        public String testB() {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "------testB";
        }
    
  • 配置RT:如果一秒钟进来的请求大于等于5,且都超过了设置的处理时间RT,那么在未来的1秒的窗口时间内,断路器会自动打开,当前微服务不可用。
    微服务之服务限流和熔断Sentinel_第13张图片

  • 通过压力测试之后,在访问就会发现异常。
    微服务之服务限流和熔断Sentinel_第14张图片

1.4.2 异常比例

当请求每秒超过或等于5个,并且每秒的异常总数占通过量的比例阈值,就会熔断,在下面的窗口期中,微服务无法进行调用。

  • 断开方式:微服务之服务限流和熔断Sentinel_第15张图片

  • 修改代码:

        @GetMapping("/testB")
        public String testB() {
            int a = 10/0;
            return "------testB";
        }
    
  • 配置:异常比例∈[0.0,1.0];
    微服务之服务限流和熔断Sentinel_第16张图片

1.4.3 异常数

当资源近一分钟异常数目超过阈值后会自动进行熔断。需要注意的是创窗口时间需要大于60s,否则状态结束后可能仍然处于熔断状态。

  • 断开方式:微服务之服务限流和熔断Sentinel_第17张图片
  • 配置:
    微服务之服务限流和熔断Sentinel_第18张图片

1.5 热点参数限流

很多时候会统计某个热点数据访问频次最高的前几个数据,并进行访问限制。
热点参数限流会统计传入的参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

  • 在controller中新建方法:

        /**
         * 热点key测试代码
         * @param p1
         * @param p2
         * @return
         */
        @GetMapping("/hot")
        @SentinelResource(value = "hot",blockHandler = "deal_hot") // 不符合配置的热点规则,由deal_hot处理
        public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                                 @RequestParam(value = "p2",required = false) String p2){
            return "hotKey" + p1 + p2;
        }
    
        /**
         * testHotKey 的 blockHandler
         * @param p1
         * @param p2
         * @param e
         * @return
         */
        public String deal_hot(String p1, String p2, BlockException e){
            return "deal_hot -> blockHandler" + p1 + p2;
        }
    
  • 在sentinel配置热点规则:
    微服务之服务限流和熔断Sentinel_第19张图片

  • 访问测试:当携带第一个参数(p1)的QPS超过1,就会执行blockHandler方法。
    微服务之服务限流和熔断Sentinel_第20张图片

  • 如果不指定fallback方法,会直接在页面抛出异常。

  • 参数例外项:指定特殊指时的限流规则与平常限流规则不同。
    例如这里,当p1 == 1时,它的阈值为500
    微服务之服务限流和熔断Sentinel_第21张图片

1.6 系统规则

Sentinel系统自适应限流从整体维度对应用入口流量进行控制。

  • 系统规则模式:

    1. Load自适应:仅对Linux/Unix-like生效,进行自适应的系统保护;
    2. CPU:当前系统CPU使用率超过阈值即触发保护系统(取值[0.0,1.0]);
    3. RT:单台机器上所有入口流量的平均RT达到阈值时即触发保护系统,单位毫秒;
    4. 并发线程数:单台机器上所有入口流量的并发线程数达到阈值时即触发保护系统;
    5. 入口QPS:单台机器上所有入口流量的QPS达到阈值时即触发保护系统。

    微服务之服务限流和熔断Sentinel_第22张图片

但是用起来很危险,比如更细粒度的划分。

1.7 @SentinelResource

  • 新建一个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() + "\t 服务不可用");
        }	
    }
    

1.7.1 按资源名称配置限流规则

  • 新建流控规则:
    微服务之服务限流和熔断Sentinel_第23张图片
    微服务之服务限流和熔断Sentinel_第24张图片
  • 测试:超过阈值执行blockHandler的方法
    微服务之服务限流和熔断Sentinel_第25张图片

1.7.2 按URL地址配置限流规则

  • RateLimitController中新增方法:

        @GetMapping("/rateLimit/byUrl")
        @SentinelResource(value = "byUrl")
        public CommonResult byUrl() {
            return new CommonResult(200, "按url限流测试OK", new Payment(2020L, "serial002"));
        }
    
  • 配置流控规则:
    微服务之服务限流和熔断Sentinel_第26张图片

  • 访问测试:由于未指定blockHandler,就会执行系统默认的。
    微服务之服务限流和熔断Sentinel_第27张图片

1.7.3 自定义限流处理逻辑

上方处理方式,仍然存在代码耦合和代码膨胀问题,且没有全局统一处理方式。

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

    public class CustomerBlockHandler {
        public static CommonResult handlerException(BlockException exception) {
            return new CommonResult(4444, "按客戶自定义,global handlerException----1");
        }
    
    
        public static CommonResult handlerException2(BlockException exception) {
            return new CommonResult(4444, "按客戶自定义,global handlerException----2");
        }
    }
    
  • RateLimitController新增方法:

        @GetMapping("/rateLimit/customerBlockHandler")
        @SentinelResource(value = "customerBlockHandler",
                blockHandlerClass = CustomerBlockHandler.class,
                blockHandler = "handlerException2")
        public CommonResult customerBlockHandler() {
            return new CommonResult(200, "按客戶自定义", new Payment(2020L, "serial003"));
        }
    
  • 配置流控规则:
    微服务之服务限流和熔断Sentinel_第28张图片

  • 测试:超过阈值执行CustomerBlockHandler.handlerException2()

    微服务之服务限流和熔断Sentinel_第29张图片

1.8 整合Ribbon

让消费者84通过ribbon实现负载均衡调用9003和9004微服务。
微服务之服务限流和熔断Sentinel_第30张图片

1.8.1 新建服务提供者微服务

  • 新建cloudalibaba-provider-payment9004cloudalibaba-provider-payment9005

  • 依赖:

       <dependencies>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
            dependency>
    
            <dependency>
                <groupId>org.examplegroupId>
                <artifactId>cloud-api-commonsartifactId>
                <version>1.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
        dependencies>
    
    
  • 配置:记得修改9005端口

    server:
      port: 9004
    
    spring:
      application:
        name: nacos-payment-provider
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #配置Nacos地址
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
  • 启动类:记得修改9005类名

    @SpringBootApplication
    @EnableDiscoveryClient
    public class NacosMain9004 {
        public static void main(String[] args) {
            SpringApplication.run(NacosMain9004.class,args);
        }
    }
    
  • 业务类:

    @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;
        }
    
    }
    
  • 访问测试:
    微服务之服务限流和熔断Sentinel_第31张图片

1.8.2 新建服务消费者微服务

  • 新建module:cloudalibaba-consumer-nacos-order84

  • 依赖:

        <dependencies>
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
    
            <dependency>
                <groupId>org.examplegroupId>
                <artifactId>cloud-api-commonsartifactId>
                <version>1.0-SNAPSHOTversion>
            dependency>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
    
    
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
        dependencies>
    
  • 配置文件:

    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
    
    # 激活Sentinel对Feign的支持
    feign:
      sentinel:
        enabled: true
    
  • 主启动类:

    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class NacosOrderMain84 {
        public static void main(String[] args) {
            SpringApplication.run(NacosOrderMain84.class, args);
        }
    }
    
  • 配置RestTmplate:

    @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;
        }
    }
    
  • 访问:可以实现轮询
    微服务之服务限流和熔断Sentinel_第32张图片

1.8.3 未配置fallback

  • 如下代码:没有指定配置fallback,
    @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;
    }
  • 访问http://localhost:84/consumer/fallback/4:可以发现没有任何处理。
    微服务之服务限流和熔断Sentinel_第33张图片

1.8.4 只配置fallback

  • 如下代码,指定fallback为handlerFallback()
        @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;
        }
    
        //本例是fallback
        public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
        }
    
  • 重启84端口后,访问http://localhost:84/consumer/fallback/4,出现自定义的fallback。
    微服务之服务限流和熔断Sentinel_第34张图片

1.8.5 只配置blackHandler

  • 代码如下:

        @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("IllegalArgumentException,非法参数异常....");
            } else if (result.getData() == null) {
                throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
            }
    
            return result;
        }
    
        //本例是blockHandler
        public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
        }
    }
    
  • 重启84端口后,访问http://localhost:84/consumer/fallback/4,可以看出blockHandlersentinel控制台配置违规。
    微服务之服务限流和熔断Sentinel_第35张图片

1.8.5 配置blackHandler和fallback

  • 代码如下:

        @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("IllegalArgumentException,非法参数异常....");
            } else if (result.getData() == null) {
                throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
            }
    
            return result;
        }
    
        //本例是fallback
        public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
        }
    
        //本例是blockHandler
        public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
        }
    
  • 重启后,访问http://localhost:84/consumer/fallback/4测试:
    微服务之服务限流和熔断Sentinel_第36张图片

  • 配置流控规则:
    微服务之服务限流和熔断Sentinel_第37张图片

  • 超出阈值,再访问http://localhost:84/consumer/fallback/1测试:
    微服务之服务限流和熔断Sentinel_第38张图片

  • 超出阈值再访问http://localhost:84/consumer/fallback/4,测试:
    微服务之服务限流和熔断Sentinel_第39张图片

  • 可以看出,被限流降级后会由blockHandler来处理。

1.8.6 异常忽略属性

  • 代码如下:

        @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("IllegalArgumentException,非法参数异常....");
            } else if (result.getData() == null) {
                throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
            }
    
            return result;
        }
    
        //本例是fallback
        public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
        }
    
        //本例是blockHandler
        public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
            Payment payment = new Payment(id, "null");
            return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
        }
    
  • 也就是说如果当前方法抛出IllegalArgumentException异常,就不会由fallback来处理,但如果限流时仍然会走blockHandler

1.9 整合OpenFeign

  • 新建接口:

    @FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
    public interface PaymentService {
        @GetMapping(value = "/paymentSQL/{id}")
        CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
    }
    
  • fallback实现类:

    @Component
    public class PaymentFallbackService implements PaymentService {
        @Override
        public CommonResult<Payment> paymentSQL(Long id) {
            return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
        }
    }
    
  • 新增controller:

    @Slf4j
    @RestController
    public class MyFeignController {
        @Resource
        private PaymentService paymentService;
    
        @GetMapping(value = "/consumer/paymentSQL/{id}")
        public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
            return paymentService.paymentSQL(id);
        }
    }
    
  • 启动84,访问:http://localhost:84/consumer/paymentSQL/4,可以访问成功。
    微服务之服务限流和熔断Sentinel_第40张图片

  • 模拟服务提供者宕机,看84会不会自动关闭调用:测试成功。
    微服务之服务限流和熔断Sentinel_第41张图片

1.10 sentinel持久化

由于默认的流控规则等,都是临时的,重启之后就消失。需要将配置的规则存入持久化容器中。

  • 将配置持久化到nacos中,只要nacos中的配置不删除,针对当前微服务配置的sentinel中的规则都不会删除。

  • 这里以8401为例

  • 新增依赖:

            <dependency>
                <groupId>com.alibaba.cspgroupId>
                <artifactId>sentinel-datasource-nacosartifactId>
            dependency>
    
  • 修改配置文件:

    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            server-addr: 49.232.141.194:8848 #Nacos服务注册中心地址
        sentinel:
          transport:
            dashboard: localhost:8080 #配置Sentinel dashboard地址
            port: 8719
          datasource:
            ds1: # 将当前微服务的sentinel配置存入到nacos持久化
              nacos:
                server-addr: localhost:8848
                dataId: ${spring.application.name}
                groupId: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
  • 在nacos中新增配置:
    微服务之服务限流和熔断Sentinel_第42张图片

  • json内容:

    [
        {
    	    "resource": "/rateLimit/byUrl",
    	    "limitApp": "default",
    	    "grade": 1,
    	    "count": 1,
    	    "strategy": 0,
    	    "controlBehavior": 0,
    	    "clusterMode": false
        }
    ]
    
  • 启动8401,在sentinel中可以看到配置的规则。
    微服务之服务限流和熔断Sentinel_第43张图片

你可能感兴趣的:(2022,#,springcloud,微服务,spring,cloud,java)