SpringCloud Alibaba Sentinel实现熔断与限流

一、Sentinel概述

1.1 官网

https://github.com/alibaba/Sentinel

中文

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

1.2 Sentinel 是什么

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

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

SpringCloud Alibaba Sentinel实现熔断与限流_第1张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第2张图片

1.3 去哪下

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

SpringCloud Alibaba Sentinel实现熔断与限流_第3张图片

1.4 能干嘛

SpringCloud Alibaba Sentinel实现熔断与限流_第4张图片

1.5 怎么玩

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

服务使用中的各种问题

  • 服务雪崩
  • 服务降级
  • 服务熔断
  • 服务限流

二、安装Sentinel控制台

2.1 Sentinel组件由两部分组成

核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo/SpringCloud等框架也有较好的支持。

控制台(Dashboard)基于SpringBoot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

  • 后台
  • 前台8080

2.2 安装步骤

2.2.1 下载

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

下载到本地sentinel-dashboard-1.7.0.jarSpringCloud Alibaba Sentinel实现熔断与限流_第5张图片

2.2.2 运行命令

前提

Java8环境OK

8080端口不能被占用

命令

java -jar sentinel-dashboard-1.7.0.jar

SpringCloud Alibaba Sentinel实现熔断与限流_第6张图片

访问sentinel管理界面

http://localhost:8080

登陆账号密码均为sentinel

SpringCloud Alibaba Sentinel实现熔断与限流_第7张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第8张图片

三、初始化演示工程

3.1 启动Nacos8848成功

SpringCloud Alibaba Sentinel实现熔断与限流_第9张图片

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

SpringCloud Alibaba Sentinel实现熔断与限流_第10张图片

3.2 新建Module

cloudalibaba-sentinel-service8401

SpringCloud Alibaba Sentinel实现熔断与限流_第11张图片

3.2.1 POM



    
        cloud2020
        com.atguigu.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    cloudalibaba-sentinel-service8401

    
        
            com.atguigu.springcloud
            cloud-api-commons
            ${project.version}
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            com.alibaba.csp
            sentinel-datasource-nacos
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
      
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            cn.hutool
            hutool-all
            4.6.3
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        

    


 

3.2.2 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
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

management:
  endpoints:
    web:
      exposure:
        include: '*'




3.2.3 主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


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

3.2.4 业务类

package com.atguigu.springcloud.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}


3.3 启动Sentinel8080

java -jar sentinel-dashboard-1.7.0

SpringCloud Alibaba Sentinel实现熔断与限流_第12张图片

http://localhost:8080/#/dashboard

3.4 启动8401微服务查看sentinel控制台

启动后,访问sentinel控制台,空空如也,啥都没有

3.4.1 Sentinel采用的懒加载说明

执行一次访问即可

http://localhost:8401/testA

http://localhost:8401/testB

效果

SpringCloud Alibaba Sentinel实现熔断与限流_第13张图片

3.4.2 结论

sentinel8080正在监控微服务8401

四、流控规则

4.1 基本介绍

SpringCloud Alibaba Sentinel实现熔断与限流_第14张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第15张图片

4.2 流控模式

4.2.1 直接(默认)

直接->快速失败

系统默认

SpringCloud Alibaba Sentinel实现熔断与限流_第16张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第17张图片

测试

1s一次没毛病

SpringCloud Alibaba Sentinel实现熔断与限流_第18张图片

狂点,限流

SpringCloud Alibaba Sentinel实现熔断与限流_第19张图片

思考

直接调用默认报错信息,技术方面OK,但是,是否应该有我们自己的后续处理?

类似有一个fallback的兜底方法。

4.2.2 关联

是什么

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

SpringCloud Alibaba Sentinel实现熔断与限流_第20张图片

用postman模拟并发密集访问testB

SpringCloud Alibaba Sentinel实现熔断与限流_第21张图片

访问testB成功

SpringCloud Alibaba Sentinel实现熔断与限流_第22张图片

postman里新建多线程集合组

SpringCloud Alibaba Sentinel实现熔断与限流_第23张图片

将访问地址添加进新线程组

SpringCloud Alibaba Sentinel实现熔断与限流_第24张图片

Run运行后发现testA挂了,大批量线程高并发访问B,导致A失效了

点击访问http://localhost:8401/testA

结果

Blocked by Sentinel (flow limiting)

4.2.3 链路

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

4.2 流控效果

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

直接失败,抛出异常

Blocked by Sentinel(flow limiting)

源码

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

4.2.2 预热

说明

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

官网

SpringCloud Alibaba Sentinel实现熔断与限流_第25张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第26张图片

默认coldFactor为3,即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值。

限流冷启动

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

源码

SpringCloud Alibaba Sentinel实现熔断与限流_第27张图片

Warmup配置

SpringCloud Alibaba Sentinel实现熔断与限流_第28张图片

多次点击http://localhost:8401/testB

刚开始不行,后续慢慢OK

应用场景

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

4.2.3 排队等待

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

SpringCloud Alibaba Sentinel实现熔断与限流_第29张图片

官网

SpringCloud Alibaba Sentinel实现熔断与限流_第30张图片

源码

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

测试

SpringCloud Alibaba Sentinel实现熔断与限流_第31张图片

五、降级规则

5.1 基本介绍

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。

当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。

SpringCloud Alibaba Sentinel实现熔断与限流_第32张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第33张图片

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

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

SpringCloud Alibaba Sentinel实现熔断与限流_第34张图片

5.2 降级策略实战

5.2.1 RT

是什么

每秒查询率(QPS,Queries-per-second)是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。

SpringCloud Alibaba Sentinel实现熔断与限流_第35张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第36张图片

测试

代码

package com.atguigu.springcloud.alibaba.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA() {
        //暂停毫秒
        try {
            TimeUnit.MILLISECONDS.sleep(800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        log.info(Thread.currentThread().getName()+"\t"+"testB");
        return "------testB";
    }

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


配置

SpringCloud Alibaba Sentinel实现熔断与限流_第37张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第38张图片

jmeter压测

SpringCloud Alibaba Sentinel实现熔断与限流_第39张图片

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

5.2.2 异常比例

是什么

SpringCloud Alibaba Sentinel实现熔断与限流_第40张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第41张图片

测试

代码

@GetMapping("/testD")
    public String testD()
    {

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

配置

jmeter

SpringCloud Alibaba Sentinel实现熔断与限流_第42张图片

结论

SpringCloud Alibaba Sentinel实现熔断与限流_第43张图片

5.2.3 异常数

是什么

SpringCloud Alibaba Sentinel实现熔断与限流_第44张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第45张图片

异常数是按照分钟统计的

测试

代码

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

配置

http://localhost:8401/testE

SpringCloud Alibaba Sentinel实现熔断与限流_第46张图片

jmeter

SpringCloud Alibaba Sentinel实现熔断与限流_第47张图片

前四次,报错

SpringCloud Alibaba Sentinel实现熔断与限流_第48张图片

五次以后,降级

SpringCloud Alibaba Sentinel实现熔断与限流_第49张图片

六、热点key限流

6.1 基本介绍

SpringCloud Alibaba Sentinel实现熔断与限流_第50张图片

6.2 官网

https://github.com/alibaba/Sentinel/wiki/热点参数限流

6.3 @SentinelResource

6.3.1 兜底方法

分为系统默认和客户自定义,两种

之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel(flow limiting)

我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?

6.3.2 结论

从HystrixCommand到@SentinelResource

6.4 代码

com.alibaba.csp.sentinel.slots.block.BlockException

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

6.5 配置

SpringCloud Alibaba Sentinel实现熔断与限流_第51张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第52张图片

异常打到了前台用户界面看不到,不友好 

@SentinelResource(value = "testHotKey")

SpringCloud Alibaba Sentinel实现熔断与限流_第53张图片

方法testHostKey里面第一个参数,只要QPS超过每秒1次,马上降级处理,用了我们自己定义的

@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")

SpringCloud Alibaba Sentinel实现熔断与限流_第54张图片

6.6 测试

只要不包含热点参数,没有限流规则,所以就不会报错

SpringCloud Alibaba Sentinel实现熔断与限流_第55张图片

6.7 参数例外项

上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流

6.7.1 特殊情况

普通

超过1秒钟一个后,达到阈值1后马上被限流

特例

我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样。假如,当p1的值等于5时,它的阈值可以达到200.

6.7.2 配置

SpringCloud Alibaba Sentinel实现熔断与限流_第56张图片

6.7.3 测试

前提条件:热点参数的注意点,参数必须是基本类型或者String

SpringCloud Alibaba Sentinel实现熔断与限流_第57张图片

 

SpringCloud Alibaba Sentinel实现熔断与限流_第58张图片

七、系统规则

7.1 是什么

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

7.2 各项配置参数说明

SpringCloud Alibaba Sentinel实现熔断与限流_第59张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第60张图片

7.3 配置全局QPS

全局性的,不具体方法,所有的

SpringCloud Alibaba Sentinel实现熔断与限流_第61张图片

八. @SentinelResource

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

8.1.1 启动Nacos成功

8.1.2 启动Sentinel成功

8.1.3 Module

cloudalibaba-sentinel-service8401

SpringCloud Alibaba Sentinel实现熔断与限流_第62张图片

POM



    
        cloud2020
        com.atguigu.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    cloudalibaba-sentinel-service8401

    
        
            com.atguigu.springcloud
            cloud-api-commons
            ${project.version}
        

        
            com.atguigu.springcloud
            cloud-api-commons
            ${project.version}
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

        
            com.alibaba.csp
            sentinel-datasource-nacos
        

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            cn.hutool
            hutool-all
            4.6.3
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        

    


 

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
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

management:
  endpoints:
    web:
      exposure:
        include: '*'




业务类

package com.atguigu.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


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

8.1.4 配置流控规则

配置步骤

SpringCloud Alibaba Sentinel实现熔断与限流_第63张图片

表示1秒钟内查询次数大于1,就跑到我们自定义的限流

8.1.5 测试

1秒钟点击1下,OK

SpringCloud Alibaba Sentinel实现熔断与限流_第64张图片

超过上述问题,疯狂点击,返回了自己定义的限流处理信息,限流发送

SpringCloud Alibaba Sentinel实现熔断与限流_第65张图片

8.1.6 额外问题

此时关闭微服务8401看看

SpringCloud Alibaba Sentinel实现熔断与限流_第66张图片

Sentinel控制台,流控规则消失了?

SpringCloud Alibaba Sentinel实现熔断与限流_第67张图片

临时/持久?如何持久化?

8.2 安装Url地址限流+后续处理

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

8.2.1 业务类

package com.atguigu.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


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

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

8.2.2 访问一次

http://localhost:8401/rateLimit/byUrl

8.2.3 Sentinel控制台配置

SpringCloud Alibaba Sentinel实现熔断与限流_第68张图片

8.2.4 测试

疯狂点击http://localhost:8401/rateLimit/byUrl

结果

SpringCloud Alibaba Sentinel实现熔断与限流_第69张图片

8.3 上面兜底方法面临的问题

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

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

SpringCloud Alibaba Sentinel实现熔断与限流_第70张图片

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

package com.atguigu.springcloud.alibaba.myhandler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;

/**
 * @author by Jak
 * @date 2020/7/3
 */
public class CustomerBlockHandler {
    public static CommonResult handleException(BlockException exception) {
        return new CommonResult(4444, "按客户自定义,global,handlerException----1");
    }

    public static CommonResult handleException2(BlockException exception) {
        return new CommonResult(4444, "按客户自定义,global,handlerException----2");
    }
}

8.4.2 RateLimitController

package com.atguigu.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.alibaba.myhandler.CustomerBlockHandler;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


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

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

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

8.4.3 启动微服务后先调用一次

http://localhost:8401/rateLimit/customerBlockHandler

SpringCloud Alibaba Sentinel实现熔断与限流_第71张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第72张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第73张图片

handlerException2兜底

SpringCloud Alibaba Sentinel实现熔断与限流_第74张图片

进一步说明

8.5 更多注解属性说明

SpringCloud Alibaba Sentinel实现熔断与限流_第75张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第76张图片

8.5.1 Define Resource

SpringCloud Alibaba Sentinel实现熔断与限流_第77张图片

8.5.2 Sentinel主要有三个核心API

  • SphU定义资源
  • Tracer定义统计
  • ContextUtil定义上下文

九、服务熔断功能

sentinel整合ribbon+openFeign+fallback

9.1 Ribbon系列

9.1.1 启动nacos和Sentinel

SpringCloud Alibaba Sentinel实现熔断与限流_第78张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第79张图片

9.1.2提供9003/9004

新建cloudalibaba-provider-payment9003/9004

SpringCloud Alibaba Sentinel实现熔断与限流_第80张图片

POM



    
        cloud2020
        com.atguigu.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    cloudalibaba-provider-payment9003

    
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.atguigu.springcloud
            cloud-api-commons
            ${project.version}
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

YML

server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author by Jak
 * @date 2020/7/3
 */
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class, args);
    }
}

业务类

package com.atguigu.springcloud.alibaba.controller;


import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;


@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    public static HashMap 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 paymentSQL(@PathVariable("id") Long id){
        Payment payment = hashMap.get(id);
        CommonResult result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }

}
 
 

测试地址

9004同上

http://localhost:9003/paymentSQL/1

http://localhost:9004/paymentSQL/1

9.1.3 消费者84

1.新建cloudalibaba-consumer-nacos-order84

SpringCloud Alibaba Sentinel实现熔断与限流_第81张图片

2.POM



    
        cloud2020
        com.atguigu.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    cloudalibaba-consumer-nacos-order84

    
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        
        
            com.atguigu.springcloud
            cloud-api-commons
            ${project.version}
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    



 

3.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

4.主启动

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;


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

5.业务类

package com.atguigu.springcloud.alibaba.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author by Jak
 * @date 2020/7/3
 */
@Configuration
public class ApplicationContextConfig {

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

 

package com.atguigu.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;


@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 fallback(@PathVariable Long id) {
        CommonResult 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);
    }


}


修改后请重启微服务

  • 热部署对java代码级生效及时
  • 对@SentinelResource注解内属性,有时效果不好

目的

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

测试地址

依次开启9003、9004、84

访问http://localhost:84/consumer/fallback/1

先出现9003,再出现9004,有轮询负载均衡算法

SpringCloud Alibaba Sentinel实现熔断与限流_第82张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第83张图片

没有任何配置

即没有熔断,也没有降级

SpringCloud Alibaba Sentinel实现熔断与限流_第84张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第85张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第86张图片

fallback/4,给客户error页面,不友好

只配置fallback

SpringCloud Alibaba Sentinel实现熔断与限流_第87张图片

访问http://localhost:84/consumer/fallback/4,不再有错误页面,返回友好提示

SpringCloud Alibaba Sentinel实现熔断与限流_第88张图片

只配置blockHandler

SpringCloud Alibaba Sentinel实现熔断与限流_第89张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第90张图片

 访问一次直接java报错

SpringCloud Alibaba Sentinel实现熔断与限流_第91张图片

快速点,满足Sentinel规则

SpringCloud Alibaba Sentinel实现熔断与限流_第92张图片

fallback和blockHandler都配置

SpringCloud Alibaba Sentinel实现熔断与限流_第93张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第94张图片

测试

一秒钟1个没问题

SpringCloud Alibaba Sentinel实现熔断与限流_第95张图片

超过1个,即使正确的也会走到限流

SpringCloud Alibaba Sentinel实现熔断与限流_第96张图片

一秒一个,有错,java异常找fallback

SpringCloud Alibaba Sentinel实现熔断与限流_第97张图片

超过1个,找blockHandler

忽略属性

IllegalArgumentException异常忽略,不走兜底。NullPointerException没有配置,走兜底

SpringCloud Alibaba Sentinel实现熔断与限流_第98张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第99张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第100张图片

9.2 Feign系列

9.2.1 修改84模块

SpringCloud Alibaba Sentinel实现熔断与限流_第101张图片

9.2.2 POM


    org.springframework.cloud
    spring-cloud-starter-openfeign

 

9.2.3 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
  
#开启sentinel对feign的支持
feign:
  sentinel:
    enabled: true

9.2.4 主启动

添加@EnableFeignClients启动Feign的功能

package com.atguigu.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;


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


9.2.5 业务类

SpringCloud Alibaba Sentinel实现熔断与限流_第102张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第103张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第104张图片

带@FeignClient注解的业务接口

package com.atguigu.springcloud.alibaba.service;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author by Jak
 * @date 2020/7/3
 */
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult paymentSQL(@PathVariable("id") Long id);
}

Controller

package com.atguigu.springcloud.alibaba.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;

import com.atguigu.springcloud.alibaba.service.PaymentService;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;


@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") //两个都配,则被限流降级而抛出BlockException时,只会进入blockHandler
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult fallback(@PathVariable Long id) {
        CommonResult 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);
    }

    //fallback
    public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
    }

    // OpenFeign
    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }
}


9.2.6 测试

SpringCloud Alibaba Sentinel实现熔断与限流_第105张图片

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

SpringCloud Alibaba Sentinel实现熔断与限流_第106张图片

9.3 熔断框架比较

SpringCloud Alibaba Sentinel实现熔断与限流_第107张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第108张图片

十、规则持久化

10.1 是什么

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

10.1.1 开启8401

SpringCloud Alibaba Sentinel实现熔断与限流_第109张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第110张图片

10.1.2 配置流控

SpringCloud Alibaba Sentinel实现熔断与限流_第111张图片

此时重启8401,刚才的配置已经没有了

SpringCloud Alibaba Sentinel实现熔断与限流_第112张图片

10.2 怎么玩

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

10.3 步骤

10.3.1 修改cloudalibaba-sentinel-service8401

10.3.2 POM


    com.alibaba.csp
    sentinel-datasource-nacos

 

10.3.3 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
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
        datasource:
          ds1:
            nacos:
              server-addr: localhost:8848
              dataId: cloudalibaba-sentinel-service
              groupId: DEAFAULT_GROUP
              data-type: json
              rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
   cloud:
    sentinel:
    datasource:
     ds1:
      nacos:
        server-addr:localhost:8848
        dataid:${spring.application.name}
        groupid:DEFAULT_GROUP
        data-type:json
            rule-type:flow
 

10.3.4 添加Nacos业务规则配置

SpringCloud Alibaba Sentinel实现熔断与限流_第113张图片

SpringCloud Alibaba Sentinel实现熔断与限流_第114张图片 

[
    {
         "resource": "/retaLimit/byUrl",
         "limitApp": "default",
         "grade":   1,
         "count":   1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
]

SpringCloud Alibaba Sentinel实现熔断与限流_第115张图片

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

SpringCloud Alibaba Sentinel实现熔断与限流_第116张图片

10.3.6 快速访问测试接口

http://localhost:8401/rateLimit/byUrl

10.3.7 停止8401再看sentinel

SpringCloud Alibaba Sentinel实现熔断与限流_第117张图片

10.3.8 重新启动8401再看sentinel

乍一看还是没有,稍等一会儿

多次调用,http://localhost:8401/rateLimit/byUrl

重新配置出现了,持久化验证通过

SpringCloud Alibaba Sentinel实现熔断与限流_第118张图片

你可能感兴趣的:(SpringCloud)