首页 > 其他分享 >Sentinel熔断与限流

Sentinel熔断与限流

时间:2023-02-03 23:35:07浏览次数:45  
标签:spring id 熔断 限流 Sentinel public cloud

1、简介

在线文档:

https://sentinelguard.io/zh-cn/docs/system-adaptive-protection.html

功能:

  • 流量控制
  • 速率控制
  • 熔断和限流

和Hystrix的区别:

  • Hystrix需要手动搭建监控平台

    (Dashboard:对Hystrix进行图形化的监控)

  • 没有web界面配置

2、快速开始

注:不能将Sentinel部署在云服务器上,因为下面的quickstart需要sentinel访问项目的ip,外网无法访问内网ip,所以我推荐你使用widnows的docker来完成下面的操作。

①安装启动

启动Nacos:

docker run --name nacos-standalone -e MODE=standalone -e JVM_XMS=256m -e JVM_XMX=256m -e JVM_XMN=128m -p 8848:8848 -d nacos/nacos-server

安装启动Sentinel:

#拉取sentinel镜像
docker pull bladex/sentinel-dashboard

#运行sentinel(docker里的sentinel是8858端口)
docker run --name sentinel -d -p 8858:8858 bladex/sentinel-dashboard

进入控制台:

image-20230202172726342

②Server工程

1.新建模块cloudalibaba-sentinel-service8401

2.依赖:

<dependencies>
    <!-- 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>
    <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>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>

3.yml:

经过我个人的测试,docker下cleint-ip设置为localhost或者127.0.0.1都会出现监控和dashboard完全相同的问题,查看网络的局域网ip填写可以正常显示

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinal-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址(改成自己的服务器ip地址,本地用localhost‍)
        #server-addr: 101.43.244.40:8848
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentin dashboard地址(改成自己的服务器ip地址,本地用localhost‍)
        dashboard: localhost:8858
        client-ip: 192.168.31.30
        #client-ip: 127.0.0.1
        # 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
        port: 8719

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

4.启动类:

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

5.Controller:

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

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

6.启动:

访问testA和testB接口

image-20230202173749299

查看sentinel控制台:

image-20230202214523148

3、流控规则

流量控制(flow control)其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

①新建流控规则

1.在流控规则处创建

image-20230203101415345

2.在簇点链路中创建

image-20230203101644883

流控效果检查:

image-20230203101723755

②阈值类型

QPS:每秒的请求数

线程数:调用该API的并发线程数

③流控模式

一.直接

对该资源进行限流

image-20230203102517401

二.关联

使用关联模式,当关联资源/testB达到了阈值1,testA也会被限流。

image-20230203103309514

删除testB的直接模式的限流,只保留关联模式限流:

因为关联模式只会对testA限流,不对testB限流,如果保留testB限流QPS条件,那么关联模式限流的阈值无法达到。

image-20230203104801870

使用Jmeter测试:

image-20230203105052486

启动Jmeter压测,访问testA接口,此时testA被限流,关联模式测试完成:

image-20230203105140367

三.链路

只针对指定的链路进行统计限流

比如testA,testB,都调用childTest接口,所以存在两条链路testA->childTest和testB->childTest。

假如我只想对testA->childTest这条链路进行限流:

注意:
Sentinel默认只标记Controller中的方法为资源,如果要标记其它方法,需要利用@SentinelResource注解

去配置文件里配置,关闭context,就可以让controller里的方法单独成为一个链路;不关闭context的话,controller里的方法都会默认进去sentinel默认的根链路里,这样就只有一条链路,无法流控链路模式,如下图所示:

image-20230203105932976

service.TestService:

@Service
public class TestService {

    @SentinelResource("childTest")
    public String childTest(){
        return "child";
    }

}

修改Controller:

@RestController
public class FlowLimitController {

    @Resource
    private TestService testService;

    @GetMapping("/testA")
    public String testA() {
        return "----testA"+testService.childTest();
    }

    @GetMapping("/testB")
    public String testB() {
        return "----testB"+testService.childTest();
    }
    
}

修改yml,关闭context(没有提示):、

这里存在问题:1.6.3-1.7.0之间的Sentinel,此注释无效

从1.6.3 版本开始,Sentinel Web filter 默认收敛所有URL的入口 context,因此链路限流不生效。

1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在 CommonFilter 引入了WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。

解决办法:

修改Springcloud alibaba的版本号:

image-20230203111539522

如果无法识别注释,为上述问题,需要解决。

image-20230203111635416

启动,如下图所示,即为关闭了context收敛:

image-20230203111839117

配置链路模式流量控制,对于childTest的testA入口进行流量限制:

image-20230203112214485

对testA入口进行压测:

image-20230203112255449

结果如下:

childTest对于testB入口无流量限制,而对于testA入口存在流量限制:

image-20230203113039135

image-20230203113228418

④流控效果

一.快速失败

直接失败,抛出异常

二.预热

应用场景:系统刚开启,秒杀等

公式:阈值/coldFacotr(默认为3)

默认冷加载因子为3,即请求QPS从threshold/3开始,经过预热时长逐渐升到设定的限流,冷启动

例:

设置预热,阈值为6,最初的阈值为6/3=2,经过10s升到6

image-20230203133651649

三.排队等待

不同于快速失败,超过QPS的会等待,设置一个超时时间,如果在时间内没有被处理,会抛出异常。

image-20230203134508721

4、降级规则

Sentinel现已支持半开状态

①慢调用比例

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

1.在Controller上添加方法:

设置休眠为1s

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

2.设置Sentinel降级为慢比例调用

image-20230203140845126

Jmeter测试:

image-20230203141257525

后面如果服务正常,可以进行半开测试,如果下一次请求小于最大响应时间,服务熔断恢复

②异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

image-20230203141843801

Controller添加异常模拟方法:

@GetMapping("/testD")
public String testD() throws Exception {
    double random = (int)(Math.random()*10);
    if (random==0) throw new Exception("异常模拟");
    log.info("testD 测试比例异常");
    return "----testD";
}

设置Sentinel服务降级为异常比例:

image-20230203143016634

测试:

使用Jmeter进行测试,当到达异常比例,进入熔断状态,5s后使用浏览器调用接口,进入半开状态,此时使用浏览器调用接口,接口返回正常,断路器从半开状态进行关闭状态。

image-20230203143215821

③异常数

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

使用②中Controller的方法,Sentinel配置:

image-20230203144134574

同②的测试,当异常数达到了一定值,进入熔断状态,5s后使用浏览器调用接口,进入半开状态,此时使用浏览器调用接口,接口返回正常,断路器从半开状态进行关闭状态。

image-20230203144618918

5、热点规则

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

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。

热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

在前面的Hystrix中,当降级时会有fallbcak方法,在Sentinel同样存在这样的兜底方法定义方式:@SentinelResource

①使用blockHandler

1.依赖(默认包含):

image-20230203145727917

2.Controller添加方法:

@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) {
    return "----testHotKey";
}

//兜底方法
public String deal_testHotKey(String p1, String p2, BlockException exception) {
    // sentinel的默认提示都是: Blocked by Sentinel (flow limiting)
    return "----deal_testHotKey, o(╥﹏╥)o";
}

Sentinel设置:

image-20230203150821230

②不使用blockHandler

不使用blockHandler,当达到阈值,进入窗口时,会直接跑出异常,返回500错误

image-20230203151510180

③参数例外项

在上面的热点规则设置中,当对应参数QPS达到一定阈值后就会被限流。对参数进行特定例外项设置,特定参数具有特地的QPS限制:

image-20230203155714521

Jmeter测试:

发起50个请求,p1=5,前40个请求正常处理,最后的10个请求出错:

image-20230203155849724

④blockHanlder与异常

不同于Hystrix的fallback,blockHandler不会自动对异常进行兜底方法处理,如果方法出错,而未满足Sentinel的控制台设置,会返回500错误

@SentinelResouce:

处理的是Sentinel控制台配置的违规情况,使用blockHandler进行兜底处理

6、系统规则

个人理解为:对整个应用的入口的流量的控制

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

对入口QPS进行限制测试:

image-20230203161607541

仅做测试,实际测试和效果不对应:

如下,QPS阈值引起的限流

image-20230203161757534

7、@SentinelResource

前置操作:

8401引入commons依赖

<dependency>
    <groupId>cn.zko0.cloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

新建一个RateLimitController

@RestController
public class RateLimitController {
}

①按资源名称限流

@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource() {
    return  new CommonResult(200,"按照资源名称限流测试",new Payment(2020L,"serial001"));
}

//兜底方法
public CommonResult handleException(BlockException exception) {
    return  new CommonResult(444,exception.getClass().getCanonicalName() + "\t 服务不可用");
}

在Sentinel中进行配置限制

image-20230203163805979

测试,成功:

QPS超过1,会使用blockHandler方法

image-20230203163908745

②按照URL地址限流

在Controller中添加接口:

@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")	//没有兜底方法,系统就用默认的
public CommonResult byUrl() {
    return  new CommonResult(200,"按照byUrl限流测试",new Payment(2020L,"serial002"));
}

在Sentinel中设置:

image-20230203164248499

测试:

image-20230203164308055

③blockHandler问题解决

blockHandler问题:

  • 系统默认,不能体现业务
  • 自定义方法和业务代码耦合在一起
  • 每个代码都需要兜底方法,代码膨胀
  • 没有全局的统一处理

解决:

自定义blockHandler类

public class CustomerBlockHandler {
    public static CommonResult handlerException(BlockException exception) {
        return  new CommonResult(444,"按照客户自定义限流测试,Glogal handlerException ---- 1");
    }

    public static CommonResult handlerException2(BlockException exception) {
        return  new CommonResult(444,"按照客户自定义限流测试,Glogal handlerException ---- 2");
    }
}

使用blockHandlerClassblockHandler对兜底方法和业务代码进行解耦:

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

在Sentinel中使用资源名称方式,进行限流(使用URL无法使用自定义兜底方法):

image-20230203164953269

测试,完成:

image-20230203165008956

8、服务熔断(Ribbon)

①Ribbon(无配置)

一.Provider

1.新建模块cloudalibaba-provider-payment9003

2.pom依赖:

<dependencies>
    <!-- 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>
    <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>cn.zko0.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </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>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>

3.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 PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class,args);
    }
}

Controller:

@RestController
public class PaymentController {

    @Value("${server.port}")    //spring的注解
    private  String serverPort;

    public static HashMap<Long, Payment> map = new HashMap<>();
    static {
        map.put(1L,new Payment(1L,"1111"));
        map.put(2L,new Payment(2L,"2222"));
        map.put(3L,new Payment(3L,"3333"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        Payment payment = map.get(id);
        CommonResult<Payment> result = new CommonResult<>(200,"from mysql,serverPort: " + serverPort,payment);
        return result;
    }

}

按照创建9003的方式创建9004

二.Consuemr

1.创建项目cloudalibaba-consumer-nacos-order84

2.pom:

<dependencies>
    <!-- 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>
    <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>cn.zko0.cloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </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>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>

3.yml:

server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  #nacos
    sentinel:
      transport:
        dashboard: localhost:8858    #sentinel
        client-ip: 192.168.31.30
        port: 8719

#消费者将去访问的微服务名称
server-url:
  nacos-user-service: http://nacos-payment-provider

#激活Sentinel对Feign的支持
#feign:
#  sentinel:
#    enabled: true

启动类:

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

RestTemplate的Config:

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

Controller:

@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("IllegalArgument,非法参数异常...");
        }else if(result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return  result;
    }
}

三.启动测试

启动

Provider:9003,9004 Consumer:84

当id在1-4范围内,服务正常调用

image-20230203204601892

当服务id>=5,调用出错:

image-20230203205819316

②Ribbon只配置fallback

在前面的Ribbon搭建的结果上,对id>=5的问题配置fallback,进行服务降级处理:

image-20230203210157168

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

测试,服务降级成功:

image-20230203210345422

③Ribbon只配置blockHandler

去掉上面fallback的配置

image-20230203210849040

//blockHandler兜底
public CommonResult blockHandler(@PathVariable Long id, BlockException e) {
    Payment payment = new Payment(id,"null");
    return new CommonResult(444,"blockHandler-sentinel 限流,BlockException: " + e.getMessage(), payment);
}

在Sentinel中配置服务降级:

image-20230203211416334

当异常数达到阈值,就会进行服务熔断

服务熔断效果:

image-20230203211612926

④Ribbon配置fallback和blockHandler

先说结论:当fallback和blockHandler同时满足,会优先调用blockHandler

同②,③,将两者配置都打开

image-20230203212010158

进行Sentinel对接口进行流量控制设置:

image-20230203213317679

测试:

当id=1,QPS未达到阈值,正常调用:

image-20230203214430518

当id=1,QPS达到阈值,调用blockHandler方法:

image-20230203214419700

当id=5,QPS未达到阈值,调用fallback方法:

image-20230203214724304

当id=5,QPS达到阈值,调用blockHandler方法:

image-20230203214750708

总结:

当@SentinelResource注解fallback和blockHandler都指定后,然后同时符合,优先执行blockHandler兜底方法。

⑤忽略属性

当在@SentinelResource中配置了exceptionsToIgnore的时候,对于该异常不会调用fallback方法,进行服务降级。

image-20230203215737786

9服务熔断(Feign)

在前面Ribbon搭建的工程上进行修改

1.需要依赖:

<!--前面已添加了-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.yml添加:

#激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true

3.启动类注解添加:

主启动类上添加@EnableFeignClients

image-20230203220653074

4.PaymentService接口

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

5.PaymentFallbackService实现类,实现PaymentService接口

其实现方法为接口中对应方法的fallback方法

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

修改Controller:

image-20230203221609696

启动:

如果你在这里出现了下图的错误
image-20230203223056990

在 Hoxton.SR1 中,fegin.context 接口的定义为 parseAndValidatateMetadata,而在 Hoxton.SR3 中,fegin.context 接口的定义为 parseAndValidateMetadata,就是之前版本中定义的方法名拼写错误,所以在 Hoxton.SR1 后面的版本更正过来,因此出现 Caused by: java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidateMetadata(Ljava/lang/Class;)Ljava/util/List; 错误。

解决方式:将 Spring Cloud 版本升至 Hoxton.SR3

image-20230203225440079

10、规则持久化

在前面的学习中,在每次停止项目的时候,Snetinel规则将会消失。所以我们需要将限流规则持久化。

我们将Sentinel规则持久化保存至Nacos中。

针对8401项目,进行修改和测试:

1.添加依赖:(之前添加过)

<!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2.yml修改:

image-20230203230055375

3.在Nacos添加Sentinel配置:

image-20230203230257145

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

上面的配置对应着Sentinel的限流配置词条:

image-20230203230415654

启动8401,去Sentinel中查看:

可以看到Nacos中配置的限流规则在启动后就能显示,完成了持久化

image-20230203230845830

标签:spring,id,熔断,限流,Sentinel,public,cloud
From: https://www.cnblogs.com/zko0/p/17090700.html

相关文章

  • Ali开源软件Sentinel的思考 Issue #59:关于线程限流问题的讨论
    interfaceLimiter{booleancanPass();voidexit();}classFlowLimiterimplementsLimiter{privateAtomicIntegeratomic;pri......
  • springboot~openfeign开启熔断之后MDC为null的解决
    上一篇说了关于MDC跨线程为null的理解,而本讲主要说一下,如何去解决它,事实上,Hystrix为我们留了这个口,我们只需要继承HystrixConcurrencyStrategy,然后重写wrapCallable方法,再......
  • 详解高并发中的限流原理和实现
    电商高并发场景下,我们经常会使用一些常用方法,去应对流量高峰,比如限流、熔断、降级,今天我们聊聊限流。什么是限流呢?限流是限制到达系统的并发请求数量,保证系统能够正常响应......
  • springboot~openfeign开启熔断之后MDC为null的理解
    openfeign开启熔断之后MDC为null,这是有前提的,首先,你的熔断开启后,使用的是线程池的熔断模式,即hystrix.command.default.execution.isolation.strategy=THREAD,或者不写这行,如......
  • ESA SNAP中超分模块处理Sentinel-2数据效果图
    原文:https://view.inews.qq.com/k/20200906A0GEO600?web_channel=wap&openApp=false欧空局SNAP中超分辨率(SuperResolution)扩展模块可以将Sentinel-2数据20米和60米波段进......
  • 10--限流技术学习 | 青训营笔记
    这是我参与「第五届青训营」伴学笔记创作活动的第10天简介所谓限流,就是指限制流量请求的频次。它主要是在高并发情况下,用于保护系统的一种策略,主要是避免在流量高峰导......
  • Java使用Semaphore对单接口进行限流
    java使用Semaphore对单接口进行限流目录一、实战说明1.1效果说明1.2核心知识点二、?环境搭建三、限流演示3.1并发请求工具3.2效果示例图一、实战说明1.1效果说明......
  • redis主从集群 -- Sentinel 哨兵
    Redis的主从集群是一个“一主多从”的读写分离集群。集群中的Master节点负责处理客户端的读写请求,而Slave节点仅能处理客户端的读请求。在采用单线程IO模型时,为了......
  • SpringCloud Alibaba之Sentinelt组件
    文章目录​​一、Sentinel熔断与限流​​​​二、控制台安装​​​​1、Sentinel控制台安装​​​​三、规则讲解​​​​1、实时监控​​​​2、流控规则​​​​2.1流控......
  • Istio 熔断限流
    Istio使用目标规则中的TrafficPolicy属性来配置熔断和限流,其中connectionPool属性配置限流方式,outlierDetection配置异常检测的熔断方式。下面,来分别看一下这二者是如......