美文网首页
Sentinel实现熔断与限流

Sentinel实现熔断与限流

作者: 码农GG | 来源:发表于2021-01-17 23:35 被阅读0次

    1.sentinel官网

    1.2官网

    https://github.com/alibaba/Sentinel
    https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
    下载源码地址

    image.png

    1.2主要特性

    image.png

    1.3使用场景

    https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
    服务使用中的各种问题
    服务雪崩;服务降级;服务熔断;服务限流

    2.安装Sentinel控制台

    2.1sentinel组件由2部分组成

    image.png

    2.2运行环境

    下载https://github.com/alibaba/Sentinel/releases (1.8v)
    sentinel-dashboard-1.8.0.jar
    java8环境;
    8080端口不能被占用(linux下开启防火墙端口)
    命令:java -jar sentinel-dashboard-1.8.0.jar

    2.3访问sentinel管理界面:

    http://localhost:8080(登录账号密码均为sentinel)

    image.png

    3.初始化演示工程

    启动Nacos8848成功

    3.1创建module

    cloudalibaba-sentinel-service8401

    3.2POM依赖

            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</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-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
          
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>4.6.3</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    3.3YML配置

    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            server-addr: 192.168.1.111:1111
        sentinel:
          transport:
            dashboard: 192.168.1.111:8080
            port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    

    3.4启动类

    @EnableDiscoveryClient  //nacos
    @SpringBootApplication
    public class MainApp8401
    {
        public static void main(String[] args) {
            SpringApplication.run(MainApp8401.class, args);
        }
    }
    

    3.5业务类FlowLimitController

    @RestController
    public class FlowLimitController
    {
        @GetMapping("/testA")
        public String testA() {
            return "------testA";
        }
        @GetMapping("/testB")
        public String testB() {
    
            return "------testB";
        }
    }
    

    启动Sentinel8080:java -jar sentinel-dashboard-1.8.0
    启动微服务8401
    启动8401微服务后查看sentienl控制台
    Sentinel采用的懒加载说明:需要执行一次调用http://localhost:8401/testA
    sentinel8080正在监控微服务8401

    image.png

    4.流控规则

    4.1新增

    image.png
    image.png

    4.2流控模式

    4.2.1系统默认

    image.png

    4.2.2测试
    快速点击访问http://localhost:8401/testA

    Blocked by Sentinel (flow limiting)直接调用默认报错信息(后续fallback的兜底方法)

    image.png

    4.3关联

    当关联的资源达到阈值时,就限流自己
    当与A关联的资源B达到阈值后,就限流自己
    B惹事,A挂了

    4.3.1配置

    image.png

    4.3.2测试
    postman模拟并发密集访问testB
    大批量线程高并发访问B,导致A失效了

    4.4链路

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

    4.4.1流控效果
    默认直接失败,抛出异常(Blocked by Sentinel (flow limiting))
    com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
    预热
    公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

    image.png
    image.png

    https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8

    4.4.2源码
    com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

    4.4.3Warmup配置

    image.png

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

    4.4.4排队等待

    image.png

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

    image.png

    com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

    5.降级规则

    image.png

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

    5.1降级策略实战RT

    image.png

    5.1.1测试

        @GetMapping("/testD")
        public String testD()
        {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            log.info("testD 测试RT");
            return "------testD";
        }
    

    5.1.2配置

    image.png
    image.png

    5.2异常比例

    image.png
    image.png

    5.2.1测试代码

    @GetMapping("/testD")
        public String testD()
        {
            log.info("testD 测试RT");
            int age = 10/0;
            return "------testD";
        }
    

    5.2.2配置

    image.png

    5.2.3结果

    image.png

    5.3异常数

    image.png
    image.png

    异常数是按照分钟统计的

    5.3.1测试

    @GetMapping("/testE")
    public String testE()
    {
        log.info("testE 测试异常数");
        int age = 10/0;
        return "------testE 测试异常数";
    }
    
    image.png

    5.4热点key限流

    官网:https://github.com/alibaba/Sentinel/wiki/热点参数限流
    @SentinelResource
    com.alibaba.csp.sentinel.slots.block.BlockException
    5.4.1代码

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }
     
    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "------deal_testHotKey,o(╥﹏╥)o";  
    }
    

    5.4.2配置

    image.png

    1.@SentinelResource(value = "testHotKey")
    异常打到了前台用户界面看不到,不友好

    2.@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    方法testHostKey里面第一个参数只要QPS超过每秒1次,马上降级处理,用了我们自己定义的

    error
    http://localhost:8401/testHotKey?p1=abc
    http://localhost:8401/testHotKey?p1=abc&p2=33
    right
    http://localhost:8401/testHotKey?p2=abc

    5.5参数例外项

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

    5.5.1配置

    image.png

    5.5.2测试
    http://localhost:8401/testHotKey?p1=5当p1等于5的时候,阈值变为200
    http://localhost:8401/testHotKey?p1=3当p1不等于5的时候,阈值就是平常的1

    6系统规则

    https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

    image.png

    6.1配置全局QPS

    @SentinelResource
    按资源名称限流+后续处理
    启动Nacos成功,启动Sentinel成功
    Module:cloudalibaba-sentinel-service8401

    6.1.1POM

    <dependency>
        <groupId>com.atguigu.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    

    6.1.2YML

    server:
      port: 8401
    
    spring:
      application:
        name: cloudalibaba-sentinel-service
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          transport:
            dashboard: localhost:8080
            port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    
    

    6.1.3业务类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 服务不可用");
        }
    

    主启动后

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

    6.2配置流控规则

    6.2.1配置步骤

    image.png

    图形配置和代码关系
    表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流

    6.2.2测试
    1秒钟点击1下,OK
    超过上述问题,疯狂点击,返回了自己定义的限流处理信息,限流发送

    按照Url地址限流+后续处理
    通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }
     
    
    image.png

    疯狂点击http://localhost:8401/rateLimit/byUrl
    会返回sentinel自带的限流处理结果

    image.png

    上面兜底方法面临的问题

    image.png

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

    6.3.1创建customerBlockHandler类用于自定义限流处理逻辑

    public class CustomerBlockHandler {
        public static CommonResult handleException(BlockException exception) {
            return new CommonResult(2020, "自定义限流处理信息....CustomerBlockHandler");
        }
    }
    

    6.3.2RateLimitController

    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
    }
    

    6.3.3启动微服务后先调用一次
    http://localhost:8401/rateLimit/customerBlockHandler
    6.3.4配置

    image.png

    7.服务熔断功能

    7.1概述

    sentinel整合ribbon+openFeign+fallback

    7.2Ribbon系列

    新建消费者cloudalibaba-provider-payment9003/9004

    7.2.1POM

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

    7.2.2YML

    server:
      port: 9003
    
    spring:
      application:
        name: nacos-payment-provider
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #配置Nacos地址
    
    management:
      endpoints:
        web:
          exposure:
            include: '*'
    

    7.2.3启动类

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

    7.2.4业务类

    @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;
        }
    }
    

    7.2.5新建消费者84
    cloudalibaba-consumer-nacos-order84
    7.2.6POM

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>cloud2020</artifactId>
            <groupId>com.atguigu.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>cloudalibaba-consumer-nacos-order84</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</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>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    7.2.6YML

    server:
      port: 84
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          transport:
            dashboard: localhost:8080
            port: 8719
    
    service-url:
      nacos-user-service: http://nacos-payment-provider
    

    7.2.7主启动类

    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class OrderNacosMain84
    {
        public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
        }
    }
    

    7.2.8业务类
    ApplicationContextConfig

    
    @Configuration
    public class ApplicationContextConfig
    {
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    }
    

    CircleBreakerController的全部源码

    
    @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") //没有配置
        //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
        //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
        @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);
        }
    }
    

    fallback管运行异常
    blockHandler管配置违规

    7.2.8测试地址
    http://localhost:84/consumer/fallback/1给客户error页面,不友好

    fallback和blockHandler都配置

    image.png

    7.3Feign系列

    7.3.1POM

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

    7.3.2YML

    server:
      port: 84
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          transport:
            dashboard: localhost:8080
            port: 8719
    
    service-url:
      nacos-user-service: http://nacos-payment-provider
    
    #对Feign的支持
    feign:
      sentinel:
        enabled: true
    

    7.3.3业务类
    带@FeignClient注解的业务接口

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

    fallback = PaymentFallbackService.class
    PaymentFallbackService实现类

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

    controller

    // OpenFeign
    @Resource
    private PaymentService paymentService;
    
    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }
    

    添加@EnableFeignClients启动Feign的功能

    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class OrderNacosMain84
    {
        public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
        }
    }
    

    http://lcoalhost:84/consumer/paymentSQL/1
    测试84调用9003,此时故意关闭9003微服务提供者,看84消费侧自动降级,不会被耗死

    7.4规则持久化

    一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
    将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效

    7.4.1步骤
    修改cloudalibaba-sentinel-service8401
    POM

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

    YML

    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:  #添加Nacos数据源配置
            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的支持
    

    7.4.2添加Nacos业务规则配置

    image.png
    image.png

    7.4.3启动8401后刷新sentinel发现业务规则有了

    image.png

    相关文章

      网友评论

          本文标题:Sentinel实现熔断与限流

          本文链接:https://www.haomeiwen.com/subject/cfhmiktx.html