Sentinel整合Ribbon/OpenFeign,Sentinel自定义限流熔断

Sentinel服务熔断环境搭建

服务熔断:应对微服务雪崩效应的一种链路保护机制,类似保险丝。

需要完成Sentinel整合Ribbon+openFeign,所以我们先要搭建环境,那么先从整合Ribbon开始

环境搭建

为了演示操作,所以在这里我们需要利用Ribbon进行负载均衡的调用,所以我们需要创建一个服务消费者spring-cloud-consumer和两个服务提供者nacos-9001/9002,以下是结构图

新建nacos-9001/9002

@SpringBootApplication
@EnableDiscoveryClient
public class Nacos9001Application {

    public static void main(String[] args) {
        SpringApplication.run(Nacos9001Application.class, args);
    }

}
@RestController
public class TestController {

    @Value("${server.port}")
    private  String port;

    @GetMapping("hello")
    public String getTest(){
        return "hello "+port;
    }
}

# 应用名称
spring.application.name=nacos-provder
#端口
server.port=9001
#用户名
spring.cloud.nacos.discovery.username=nacos
#密码
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#暴露所有端点
management.endpoints.web.exposure.include=*
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

新建spring-cloud-consumer

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudConsumerApplication.class, args);
    }


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

@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${server.url.name}")
    private String serverName;

    @GetMapping("ribbon")
    public String handerConcumer(){
        return restTemplate.getForObject(serverName+"/hello",String.class);
    }
}

# 应用名称
spring.application.name=spring-cloud-consumer
server.port=8084

spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public

# Sentinel 控制台地址
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.web-context-unify=false
# 取消Sentinel控制台懒加载
spring.cloud.sentinel.eager=true
server.url.name=http://nacos-provder

测试

在这里插入图片描述

Sentinel整合OpenFegin

根据之前的学习,我们已经学习过了包括Sentinel整合Ribbon,包括对OpenFegin的基本学习,那么这节课,我们就需要通过Sentinel来进行整合OpenFegin

日志级别:

  • NONE:默认的,不显示任何日志;

  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;

  • HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;

  • FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
# 激活SentinelOpenFeign的支持
feign.sentinel.enabled=true
ribbon.ReadTimeout=5000
ribbon.ConnectionTimeout=5000
logging.level.com.openfeign.springcloudopenfeign.service.TestService=debug
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudConsumerApplication.class, args);
    }
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

@FeignClient("nacos-provder")
public interface OpenFeignApi {

    @GetMapping("hello")
    public String getTest();
}

@RestController
public class OpenFeignController {

    @Autowired
    private OpenFeignApi openFeignApi;

    @GetMapping("openFeign")
    public String getProvider() {
        return openFeignApi.getTest();
    }
}

在这里插入图片描述

fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口

  1. 9001服务自定义一个异常

  2. @FeignClient增加fallback = OpenFeignService.class 属性

  3. 新建一个异常处理类

    @Component
    public class OpenFeignService implements OpenFeignApi{
        @Override
        public String getTest() {
            return "服务不可用";
        }
    }
    
    
  4. 查看结果

    在这里插入图片描述

SentinelResource的fallback属性

​Sentinel 提供了@SentinelResource注解用于定义资源,并提供了AspectJ的扩展用于自定义资源,处理BlockException等。

  • value:资源名称,必须项(唯一,不能为空)
  • blockHandler:对应处理BlockException的函数名称可选项lockHandler函数访问需要public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException.blockHandler 函数默认需要和原方法在同一个类中
@SentinelResource 资源限流

核心点: 使用@SentinelResource注解的blockHandler属性,定义出现限流效果时的解决方法。

@RestController
public class TestController {

    @GetMapping("/test")
    @SentinelResource(value = "test",blockHandler = "testHandler")
    public String test(@RequestParam(value ="userName",required = false ) String userName,@RequestParam(value = "pwd",required = false) String pwd){
        User user=new User();
        user.setUserName(userName);
        user.setPwd(pwd);
        return "正常结束  data="+user.toString();
    }

    public String testHandler(String userName,String pwd, BlockException e){

        return "特殊处理";
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@SentinelResource URL限流

核心点: 使用@SentinelResource注解,但是不使用blockHandler属性,系统会调用默认限流异常处理方法。

@RestController
public class TestController {

    @GetMapping("/test")
    @SentinelResource(value = "test")
    public String test(@RequestParam(value ="userName",required = false ) String userName,@RequestParam(value = "pwd",required = false) String pwd){
        User user=new User();
        user.setUserName(userName);
        user.setPwd(pwd);
        return "正常结束  data="+user.toString();
    }
}

在这里插入图片描述
在这里插入图片描述

结论
  1. @SentinelResource 既可以配置资源名称也可以配置URL
  2. 如果配置了@SentinelResource的blockHandler属性对应方法,出现限流会调用对应方法
  3. 如果没有配置@SentinelResource的blockHandler属性,系统会走默认的限流处理。

自定义限流处理逻辑

其实我们在使用@SentinelResource注解这两种方案的时候,会出现一些问题:

  1. 没有体现我们自己的业务要求。
  2. 自定义处理方法和业务代码耦合在一起。
  3. 每个业务方法都添加一个限流处理方法,代码将会加剧膨胀。
  4. 无法实现统一全局处理。

解决:@SentinelResource除了blockHandler可以设置自定义限流处理逻辑方法以外,还提供另外一个属性来设置限流处理逻辑类型blockHandlerClass属性,此属性中设置的方法必需为 static 函数,否则无法解析。

第一步

创建CustomHandler 类型用于处理自定义限流处理逻辑


public  class CustomHandler {

    public static String handlerException1(BlockException exception) {
        return "handlerException1:系统异常,请稍后重试!";
    }

    public static String handlerException2(BlockException exception) {
        return "handlerException2:网络崩溃了,请稍后重试!";
    }
}

第二步

我们在CustomerBlockHandlerController类型中添加一个接口方法,同时设置@SentinelResource注解和blockHandlerClass属性对应的类型和这个类型中对应的处理方法

@RestController
public class CustomerBlockHandlerController {

    @GetMapping("customer")
    @SentinelResource(value = "customer",
                        blockHandlerClass = CustomHandler.class,
                        blockHandler = "handlerException1")
    public String testA() {
        return "customer";
    }
}

第三步

测试:给bycustomer资源添加限流规则,然后来测试在超过限流阈值时处理方法是否为CustomHandler 中handlerException1来进行处理。
在这里插入图片描述

在这里插入图片描述

SentinelResource的fallback属性

fallback属性

概念: fallback 函数名称,可选项,用于在抛出异常的时候提供fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:

  • 返回值类型必须与原函数返回值类型一致;
  • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
  • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

其实通过官网上提供的概念,我们不难看出这个属性类似于blockHandler,但是各位一定要注意他们有本质的不同。

注意: fallback属性和blockHandler属性的本质不同在于他们作用的异常不同:

  • blockHandler:针对违反Sentinel控制台配置规则时触发BlockException异常时对应处理的属性
  • fallback:针对Java本身出现的异常进行处理的对应属性。
@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${server.url.name}")
    private String serverName;

    @GetMapping("ribbon")
    public String handerConcumer(@RequestParam(value = "id", required = false) Integer id) throws Exception {
        if (id != null && id > 3) {
            throw new Exception("系统出问题了");
        }
        return restTemplate.getForObject(serverName + "/hello", String.class);
    }
}

在这里插入图片描述

明显此时显示效果非常不好,我们就可以通过@SentinelResource注解的fallback属性来解决这种java异常,给出友好提示

@GetMapping("ribbon")
@SentinelResource(value = "ribbon", fallback = "fallBackException")
 public String handerConcumer(@RequestParam(value = "id", required = false) Integer id) throws Exception {
     if (id != null && id > 3) {
         throw new Exception("系统出问题了");
     }
     return restTemplate.getForObject(serverName + "/hello", String.class);
 }

 public String fallBackException(Integer id, Throwable e) {

     return "服务暂时不可用";
 }

在这里插入图片描述

到这里为止,我们就很清楚的知道了fallback属性的作用,同时它和blockHandler属性类似,也可以设置fallbackClass属性,来指定对应类型,来处理对应的Java异常,当然要注意和blockHandlerClass属性一样,也需要让所有的方法都必需为 static 函数,否则无法解析。

同时配置blockHandler和fallback属性

通过上述的内容,我们很清楚的知道了fallback属性的作用,但是大家现在想一个问题,如果我们在使用@SentinelResource属性的时候,同时设置blockHandler属性和fallback属性时,并且同时出现了Sentinel异常和Java异常,这个时候会执行哪个方法那。

	@GetMapping("ribbon")
    @SentinelResource(value = "ribbon", fallback = "fallBackException", blockHandler = "handlerException")
    public String handerConcumer(@RequestParam(value = "id", required = false) Integer id) throws Exception {
        if (id != null && id > 3) {
            throw new Exception("系统出问题了");
        }
        return restTemplate.getForObject(serverName + "/hello", String.class);
    }

    public String fallBackException(Integer id, Throwable e) {

        return "fallBack 服务暂时不可用";
    }

    public String handlerException(Integer id,BlockException exception) {
        return "blockHandlerException:系统异常,请稍后重试!";
    }


在这里插入图片描述

在这里插入图片描述

  • 在没有触发熔断之前的异常交给fallback来处理
  • 但是一旦触发熔断规则就变成了blockHandler来处理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值