《SpringCloud Alibaba 微服务架构》专题(十六)-Spring Cloud AlibabaSentinel之服务熔断

1.前言

前面一篇文章我们介绍了如何使用@SentinelResource定义一个资源并且如何配置降级规则等,我们都知道,微服务之间的调用要么采用ribbon借助RestTemplate进行调用,要么是通过OpenFeign声明式服务调用,涉及到跨服务调用,难免会出现网络故障,此时如果我们的接口报错,直接将报错信息展示到前端,客户看到很不友好。Sentinel提供了丰富的熔断之后的降级处理方法,本篇文章将SentinelRibbon负载均衡、SentinelOpenFeign进行整合,分别介绍如何配置处理降级。

2.服务提供者搭建

新建一个子模块工程【springcloudalibaba-provider-payment9003】和【springcloudalibaba-provider-payment9004】作为我们的服务提供者,两个子模块代码除了端口不一致,其他一模一样,下面以【springcloudalibaba-provider-payment9003】为例说明

【a】pom.xml

<?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>springcloud-alibaba-nacos</artifactId>
        <groupId>com.bruce.springcloud-alibaba-nacos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloudalibaba-provider-payment9003</artifactId>

    <dependencies>

        <!-- Alibaba-nacos服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>nacos-client</artifactId>
                    <groupId>com.alibaba.nacos</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- nacos-client -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.2.0</version>
        </dependency>

        <!-- hystrix断路器 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <!-- openfeign客户端 ,默认集成并开启了ribbon负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!--排除tomcat依赖 -->
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--undertow容器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>

        <!-- lombok插件 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

【b】application.yml配置文件

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

【c】主启动类

package com.bruce;

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

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

【d】controller业务层方法

package com.bruce.controller;

import com.bruce.pojo.JsonResult;
import com.bruce.pojo.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;

    /**
     * 模拟静态数据
     */
    private static HashMap<Long, Payment> hashMap = new HashMap<Long, Payment>();

    static {
    
    
        hashMap.put(1L, new Payment(1L, "001"));
        hashMap.put(2L, new Payment(2L, "002"));
        hashMap.put(3L, new Payment(3L, "003"));
    }

    @GetMapping(value = "/payment/{id}")
    public JsonResult<Payment> payment(@PathVariable("id") Long id) {
    
    
        Payment payment = hashMap.get(id);
        if (id.toString().equals("4")) {
    
    
            System.out.println("输出异常");
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常......");
        } else if (payment == null) {
    
    
            throw new NullPointerException("NullPointerException,该ID没有对应记录......");
        }
        return new JsonResult(200, "serial: " + payment.getAccount() + ",serverPort:  " + serverPort, payment);
    }

}

【e】测试

启动90039004服务提供者,浏览器访问:http://localhost:9003/payment/1
在这里插入图片描述
http://localhost:9004/payment/3
在这里插入图片描述
可见,接口都成功返回数据,至此我们的服务提供方【9003和9004】也就搭建成功。

3.搭建服务消费者

新建子模块【springcloudalibaba-consumer-nacos-order84】,作为我们的服务消费者。

【a】pom.xml依赖

<?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>springcloud-alibaba-nacos</artifactId>
        <groupId>com.bruce.springcloud-alibaba-nacos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloudalibaba-consumer-nacos-order84</artifactId>

    <dependencies>

        <!-- Alibaba-nacos服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>nacos-client</artifactId>
                    <groupId>com.alibaba.nacos</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- nacos-client -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.2.0</version>
        </dependency>

        <!-- hystrix断路器 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <!-- openfeign客户端 ,默认集成并开启了ribbon负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <!--排除tomcat依赖 -->
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--undertow容器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>

        <!-- lombok插件 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

【b】application.yml配置文件

server:
  port: 84
spring:
  application:
    name: springcloudalibaba-consumer-nacos-order
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  #配置nacos服务器地址
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

【c】主启动类

package com.bruce;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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

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

【d】业务controller方法

import javax.annotation.Resource;
 
@RestController
public class CircleBreakerController {
    
    
    /**
     * 指定服务提供者的微服务名称
     */
    private static final String SERVICE_URL = "http://springcloudalibaba-provider-payment";
 
    /**
     * 负载均衡调用类
     */
    @Resource
    private RestTemplate restTemplate;
 
    /**
     * 没有配置fallback和blockHandler
     */
    @RequestMapping("/consumer/noFallback/{id}")
    @SentinelResource(value = "noFallback") //没有配置
    public JsonResult<Payment> noFallback(@PathVariable Long id) {
    
    
        JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
        if (id == 4) {
    
    
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常......");
        } else if (result.getData() == null) {
    
    
            throw new NullPointerException("NullPointerException,暂未找到对应记录......");
        }
        return result;
    }
 
}

【e】测试

启动服务提供者90039004项目以及服务消费者84服务,当nacos服务注册列表看到三个服务都成功注册之后
在这里插入图片描述
浏览器访问:http://localhost:84/consumer/noFallback/1
在这里插入图片描述
在这里插入图片描述

根据运行结果,我们发现,服务消费者84已经成功实现了对服务提供者8003和8004的负载均衡调用,默认采用轮训的方式进行调用,至此我们的服务消费方也算搭建成功。

下面我们详细介绍五种不同配置下的服务熔断处理方法。

4.Sentinel服务熔断 - 没有配置fallback和blockHandler

【a】控制层增加如下代码

 /**
    * 没有配置fallback和blockHandler
    */
   @RequestMapping("/consumer/noFallback/{id}")
   @SentinelResource(value = "noFallback") //没有配置
   public JsonResult<Payment> noFallback(@PathVariable Long id) {
    
    
       JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
       if (id == 4) {
    
    
           throw new IllegalArgumentException("IllegalArgumentException,非法参数异常......");
       } else if (result.getData() == null) {
    
    
           throw new NullPointerException("NullPointerException,暂未找到对应记录......");
       }
       return result;
   }

【b】测试

浏览器访问:http://localhost:84/consumer/noFallback/2
在这里插入图片描述
当我们id = 4时,根据上面的程序判断将会抛出非法参数异常,浏览器访问:http://localhost:84/consumer/noFallback/4
在这里插入图片描述
当我们id = 5时,根据上面的程序判断将会抛出空指针异常,浏览器访问:http://localhost:84/consumer/noFallback/5
在这里插入图片描述
【c】小总结

由上面的测试结果可以看到,当我们什么都没有配置的时候,如果发生异常,那么异常信息将直接展示到前台给客户,很不友好。

5.Sentinel服务熔断 - 只配置fallback

【a】业务层增加如下方法

/**
  * fallback只负责业务异常
  */
 @RequestMapping("/consumer/fallback/{id}")
 @SentinelResource(value = "fallback", fallback = "handlerFallback")
 public JsonResult<Payment> fallback(@PathVariable Long id) {
    
    
     JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
     return result;
 }
 
 /**
     * 业务异常兜底降级方法
     */
    public JsonResult handlerFallback(@PathVariable Long id, Throwable e) {
    
    
        Payment payment = new Payment(id, "null");
        return new JsonResult<>(444, "[业务异常兜底降级方法],exception内容:  " + e.getMessage(), payment);
    }

【b】测试

浏览器访问:http://localhost:84/consumer/fallback/1在这里插入图片描述
当我们id = 4时,根据上面的程序判断将会抛出非法参数异常,浏览器访问:http://localhost:84/consumer/fallback/4
在这里插入图片描述
当我们id = 5时,根据上面的程序判断将会抛出空指针异常,浏览器访问:http://localhost:84/consumer/fallback/5
在这里插入图片描述
【c】小总结

当我们配置了fallback属性后,如果程序发生Java异常,那么错误信息将不会展示到前台展示,它将执行我们指定的业务异常兜底降级方法,错误信息可以自定义,比如提示 “服务器异常,请稍后重试” 等等,比起前面一种方式显然友好很多。

6.Sentinel服务熔断 - 只配置blockHandler

【a】业务层增加如下方法

   /**
     * blockHandler只负责sentinel控制台配置的违规情况,业务运行时异常sentinel不管,该抛出还是抛出
     */
    @RequestMapping("/consumer/withBlockHandler/{id}")
    @SentinelResource(value = "withBlockHandler", blockHandler = "blockHandler")
    public JsonResult<Payment> withBlockHandler(@PathVariable Long id) {
    
    
        JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
        return result;
    }
 
/**
     * sentinel控制台配置违反兜底降级方法
     */
    public JsonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    
    
        return new JsonResult<>(445, "[sentinel控制台配置违反兜底降级方法],无此流水: blockException  " + blockException.getMessage(), new Payment(id, "null"));
    }

【b】Sentinel配置
在这里插入图片描述
【c】测试

浏览器访问:http://localhost:84/consumer/withBlockHandler/1
在这里插入图片描述
可以看到,如果一秒钟访问一次,接口是没有问题的。但是如果我们1秒内访问多次该接口:http://localhost:84/consumer/withBlockHandler/1:
在这里插入图片描述
可以看到,当违反了sentinel控制台配置的降级规则时,将会触发blockHandler方法指定的降级处理逻辑。

下面我们看看blockHandler是否会管业务运行时异常?

当我们id = 4时,根据上面的程序判断将会抛出非法参数异常,浏览器访问:http://localhost:84/consumer/withBlockHandler/4
在这里插入图片描述
当我们id = 5时,根据上面的程序判断将会抛出空指针异常,浏览器访问:http://localhost:84/consumer/withBlockHandler/5
在这里插入图片描述
我们发现,当配置了blockHandler的时候,它只会针对违反sentinel控制台的降级规则生效,对于业务运行时抛出的异常,blockHandler是不会进行降级处理的。

【d】小总结

当配置了blockHandler的时候,它只会针对违反sentinel控制台降级规则的情况下生效,对于业务运行时抛出的异常,blockHandler是不会进行降级处理的,依旧会把运行时异常直接展示给客户页面,不太友好。

7.Sentinel服务熔断 - 配置fallback和blockHandler

【a】业务层增加如下方法

/**
     * blockHandler只负责sentinel控制台配置的违规情况,业务运行时异常sentinel不管,该抛出还是抛出
     * fallback只负责业务异常
     */
    @RequestMapping("/consumer/withBlockHandlerAndFallback/{id}")
    @SentinelResource(value = "withBlockHandlerAndFallback", fallback = "handlerFallback", blockHandler = "blockHandler",)
    public JsonResult<Payment> withBlockHandlerAndFallback(@PathVariable Long id) {
    
    
        JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
        return result;
    }
 
    /**
     * 业务异常兜底降级方法
     */
    public JsonResult handlerFallback(@PathVariable Long id, Throwable e) {
    
    
        Payment payment = new Payment(id, "null");
        return new JsonResult<>(444, "[业务异常兜底降级方法],exception内容:  " + e.getMessage(), payment);
    }
 
    /**
     * sentinel控制台配置违反兜底降级方法
     */
    public JsonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    
    
        return new JsonResult<>(445, "[sentinel控制台配置违反兜底降级方法],无此流水: blockException  " + blockException.getMessage(), new Payment(id, "null"));
    }

【b】sentinel配置
在这里插入图片描述
【c】测试

浏览器访问:http://localhost:84/consumer/withBlockHandlerAndFallback/2
在这里插入图片描述
可以看到,如果一秒钟访问一次,接口是没有问题的。但是如果我们1秒内访问多次该接口:
在这里插入图片描述
可以看到,当违反了sentinel控制台配置的降级规则时,将会触发blockHandler方法指定的降级处理逻辑。 下面我们来看看业务异常怎么处理?同上,

当我们id = 4时,根据上面的程序判断将会抛出非法参数异常,浏览器访问:http://localhost:84/consumer/withBlockHandlerAndFallback/4
在这里插入图片描述
当我们id = 5时,根据上面的程序判断将会抛出空指针异常,浏览器访问:http://localhost:84/consumer/withBlockHandlerAndFallback/5
在这里插入图片描述

【c】小总结

由前面的测试结果可以看到,当同时配置了fallback和blockHandler的时候,两者并不冲突,各处理各的。blockHandler处理sentinel控制台违反规则的降级处理;fallback处理业务运行时异常的降级处理。

注意:如果是疯狂访问:http://localhost:84/consumer/withBlockHandlerAndFallback/5,很明显,程序会抛出异常,并且也违反了sentinel控制台降级规则,小伙伴们注意,这时候,是以blockHandler降级处理为准的。

8.Sentinel服务熔断 - 配置exceptionsToIgnore

【a】业务层方法增加如下配置:使用exceptionsToIgnore属性来排除某些异常,意思就是假如程序抛出该异常时,不再进入业务异常降级处理方法,没有降级效果。

/**
 * blockHandler只负责sentinel控制台配置的违规情况,业务运行时异常sentinel不管,该抛出还是抛出
 * fallback只负责业务异常
 */
@RequestMapping("/consumer/withBlockHandlerAndFallback/{id}")
@SentinelResource(value = "withBlockHandlerAndFallback", fallback = "handlerFallback", blockHandler = "blockHandler",
        exceptionsToIgnore = {
    
    IllegalArgumentException.class})
public JsonResult<Payment> withBlockHandlerAndFallback(@PathVariable Long id) {
    
    
    JsonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/payment/" + id, JsonResult.class, id);
    return result;
}

【b】测试

当我们id = 4时,根据上面的程序判断将会抛出非法参数异常,也即是我们上面忽略的这个异常,浏览器访问:http://localhost:84/consumer/withBlockHandlerAndFallback/4添加链接描述
在这里插入图片描述
可以看到,当程序抛出IllegalArgumentException异常时,将不再走fallback降级处理方法。

浏览器访问:http://localhost:84/consumer/withBlockHandlerAndFallback/5
在这里插入图片描述
可以看到,处理上面排除的异常,其他异常还是继续会走降级处理。

【c】小总结

exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。使用exceptionsToIgnore属性来排除某些异常,意思就是假如程序抛出该异常时,不再进入业务异常降级处理方法,没有降级效果。

9.Sentinel服务熔断OpenFeign

前面我们介绍了Sentinel和Ribbon负载均衡结合起来,并通过示例详细介绍了五种服务降级的配置以及各自产生的效果。接下来我们介绍一些Sentinel整合OpenFeign远程服务调用实现服熔断降级。所以需要对【springcloudalibaba-consumer-nacos-order84】进行改造:

【a】pom.xml依赖:加入open-feign依赖

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

【b】application.yml配置文件:加入feign对sentinel的支持

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

【c】主启动类加上注解

@EnableDiscoveryClient
@SpringBootApplication
//开启远程调用
@EnableFeignClients
public class SpringCloudAlibabaConsumerOrderServiceApplicaiton84 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringCloudAlibabaConsumerOrderServiceApplicaiton84.class, args);
    }
}

【d】编写FeignClient接口

import com.wsh.springcloud.alibaba.feign.fallback.PaymentFeignClientFallback;
import com.wsh.springcloud.common.JsonResult;
import com.wsh.springcloud.entity.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 

@FeignClient(value = "springcloudalibaba-provider-payment", fallback = PaymentFeignClientFallback.class)
public interface PaymentFeignClient {
    
    
 
    @GetMapping(value = "/payment/{id}")
    Object payment(@PathVariable("id") Long id);
 
}

【e】编写FeignClient接口失败回调类


import com.wsh.springcloud.alibaba.feign.PaymentFeignClient;
import com.wsh.springcloud.common.JsonResult;
import com.wsh.springcloud.entity.Payment;
import org.springframework.stereotype.Component;
 

@Component
public class PaymentFeignClientFallback implements PaymentFeignClient {
    
    
    @Override
    public Object payment(Long id) {
    
    
        return new JsonResult<>(500, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

【f】业务controller新增如下方法

@Resource
private PaymentFeignClient paymentFeignClient;

@GetMapping(value = "/consumer/openfeign/payment/{id}")
public Object payment(@PathVariable("id") Long id) {
    
    
    Object payment = paymentFeignClient.payment(id);
    return payment;
}

【g】测试

重启服务消费者84服务,浏览器访问:http://localhost:84/consumer/feignFallback/1
在这里插入图片描述
可见,接口成功返回数据,证明我们远程调用成功。

下面我们关闭两个服务提供者9003和9004,再次访问:http://localhost:84/consumer/feignFallback/1
在这里插入图片描述

可以看到,此时调用了服务降级,说明OpenFeign的fallback处理逻辑生效了,这就实现了sentinel与openfeign的服务降级处理。

10.总结

本篇文章通过将Sentinelribbonopenfeign进行整合,实现了跨服务调用之间的接口的熔断降级处理,并分析了几种不同的配置情况下,Sentinel是如何处理降级的,在实际项目中,推荐fallback和blockHandler都进行配置,这样就能兼容业务异常和sentinel流控规则违反情况的降级处理。

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/113978203