服务之间互相调用时,如果A服务连续N次都无法访问到B服务,当N的值超过阈值时,将会熔断,之后会直接禁止对B服务的访问。举个例子来说就是当你请求A服务提供的某个接口,此时A服务通过调用B服务进行处理,但是由于网络故障,A服务一连多次都调用B服务失败,之后你再次请求A服务时,A服务将不再向B服务发送请求,A服务会直接告诉你请求失败,有效降低了故障对系统的影响。此时A服务不再请求B服务,但是又不能让他告诉我一个莫名其妙的错误,因此我们可以在熔断之后让他返回固定默认值,这就是降级。
在这里,这里我只演示使用Feign远程调用时的熔断降级功能。
具体步骤
接着前面文章中的项目,创建一个支持熔断降级的服务消费者模块,模块名为service-sentinel-feign-consumer。
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>top.jiangqiang</groupId> <artifactId>spring-cloud-demo</artifactId> <version>${revision}</version> </parent> <artifactId>service-sentinel-feign-consumer</artifactId> <name>${project.artifactId}</name> <description>service-sentinel-feign-consumer</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <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> <!--必须依赖,用于负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <!--使用feign调用接口时必须依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--流量控制,熔断降级--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> </dependencies> </project>
application.yaml文件配置如下:
server: port: 8005 spring: application: name: service-sentinel-feign-consumer cloud: sentinel: transport: #使用sentinel控制台时需要配置 port: 8719 dashboard: localhost:8080 nacos: username: @nacos.username@ #@***@这种写法表示从pom.xml文件读取配置 password: @nacos.password@ config: file-extension: yaml server-addr: @nacos.server-addr@ #用于管理配置的nacos服务地址 namespace: @nacos.namespace@ #命名空间 discovery: server-addr: @nacos.server-addr@ #服务发现,服务注册中心地址,因为和配置中心使用同一个nacos,所以地址是同一个。 namespace: @nacos.namespace@ loadbalancer: #使用 Spring Cloud Alibaba 社区针对 Spring Cloud Loadbalancer 负载均衡依赖提供的负载均衡策略,以便使用 Spring Cloud Alibaba 提供的所有的能力 ribbon: enabled: false nacos: #使用nacos提供的负载均衡,不使用此配置时,默认的负载均衡是轮询 enabled: true config: import: #springboot3必须配置此选项,至少配置一个,可以任意配置,配置后会使用nacos配置中心对应的配置 - optional:nacos:${spring.application.name}.yaml #前面加optional表示可选,允许配置服务器连接不成功时启动服务 - nacos:datasource.yaml?refresh=true #?refresh=true表示配置更新不需要重启即可生效,可以省略 - nacos:common.yaml feign: sentinel: enabled: true #feign结合sentinel使用 management: endpoints: web: exposure: include: '*' #允许所有的endpoints访问
注意这几行配置:启用sentinel针对Feign的自动配置,sentinel是一个专门用于限流和熔断降级控制的框架,底层已经完美兼容了feign的写法。
feign: sentinel: enabled: true #feign结合sentinel使用
启动类如下:
//该注解可以省略 @EnableDiscoveryClient @SpringBootApplication //使用feign客户端时必须 @EnableFeignClients public class ServiceSentinelFeignConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceSentinelFeignConsumerApplication.class, args); } }
服务降级后的处理逻辑代码:
public class FeignServiceFallback implements FeignService { @Override public String getPort() { return "获取端口号失败,熔断降级生效"; } }
将降级后的处理逻辑注入为一个Bean,但是这里还没有真的注入,因为类上并没有加
@Configuration
注解。这里其实通过该注解也可以实现功能。public class FeignConfiguration { @Bean public FeignServiceFallback echoServiceFallback() { return new FeignServiceFallback(); } }
编写FetchService代码:
/** * configuration后面配置的类中可以使用@Bean注入对象,也可以直接在对应的类上使用@Configuration注解 */ @FeignClient(name = "service-provider", fallback = FeignServiceFallback.class, configuration = FeignConfiguration.class) public interface FeignService { @GetMapping(value = "/getPort") String getPort(); }
编写一个Controller类
@RestController @RequestMapping("/") @RequiredArgsConstructor public class TestController { private final FeignService feignService; /** * 支持熔断降级 * @return */ @RequestMapping(value = "/getPort1") public String getPort1() { return "Feign:" + feignService.getPort(); } }
先启动两个服务提供者,然后访问localhost:8005/getPort1看看能否正常访问,此时通过nacos将两个服务提供者均下线,再访问该地址看看会发生什么。我们可以发现,服务发生了降级,执行了我们编写的降级后的逻辑。
评论区