关于feign client触发熔断的异常
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于feign client触发熔断的异常相关的知识,希望对你有一定的参考价值。
参考技术A 使用feign client进行restful服务间的调用,除了要注意超时时间、retry的设置外,还有一个关于自定义异常的部分,需要注意一下,不然容易出错。Nginx 默认判断失败节点状态以connect refuse和time out状态为准,不以HTTP错误状态进行判断失败,因为HTTP只要能返回状态说明该节点还可以正常连接,所以nginx判断其还是存活状态;除非添加了proxy_next_upstream指令设置对404、502、503、504、500和time out等错误进行转到备机处理。
这个异常主要是用来适配IllegalArgumentException这类异常。HystrixBadRequestException与其他HystrixCommand抛出的异常不同,该异常不会纳入circuit breaker的统计里头,即不会触发熔断。
/Users/xixicat/.m2/repository/io/github/openfeign/feign-core/9.3.1/feign-core-9.3.1-sources.jar!/feign/SynchronousMethodHandler.java
其中对status code的处理见这段
要特别注意,对于restful抛出的4xx的错误,也许大部分是业务异常,并不是服务提供方的异常,因此在进行feign client调用的时候,需要进行errorDecoder去处理,适配为HystrixBadRequestException,好避开circuit breaker的统计,否则就容易误判,传几个错误的参数,立马就熔断整个服务了,后果不堪设想。
Feign + Hystrix 服务熔断和服务降级
本机IP为 192.168.1.102
1. 新建 Maven 项目 feign
2. pom.xml
<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"> <modelVersion>4.0.0</modelVersion> <groupId>com.java</groupId> <artifactId>feign</artifactId> <version>1.0.0-SNAPSHOT</version> <name>${project.artifactId}</name> <!-- 配置版本常量 --> <properties> <jdk.version>1.8</jdk.version> <spring.cloud.version>2.0.0.RELEASE</spring.cloud.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>${spring.cloud.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>${spring.cloud.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.49</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- 热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> <version>1.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
3. application.yml
server: port: 80 feign: hystrix: enabled: true eureka: client: register-with-eureka: false service-url: defaultZone: http://192.168.1.102:8080/eureka/ #defaultZone: http://s0.com:8080/eureka/,http://s1.com:8080/eureka/,http://s2.com:8080/eureka/
4. HostService.java
package com.java.feign.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import com.alibaba.fastjson.JSONObject; @FeignClient(value = "MICROSERVICE", fallbackFactory = HostServiceFallbackFactory.class) public interface HostService { @GetMapping("/getHostMessage/{id}") public JSONObject getHostMessage(@PathVariable(value = "id") String id); }
5. HostServiceFallbackFactory.java
package com.java.feign.service; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import feign.hystrix.FallbackFactory; @Component public class HostServiceFallbackFactory implements FallbackFactory<HostService> { @Override public HostService create(Throwable cause) { return new HostService() { @Override public JSONObject getHostMessage(String id) { JSONObject json = new JSONObject(); json.put("id", id); json.put("description", "服务异常演习专用!"); json.put("msg", cause.getMessage()); return json; } }; } }
6. HostController.java
package com.java.feign.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import com.alibaba.fastjson.JSONObject; import com.java.feign.service.HostService; @RestController public class HostController { @Autowired private HostService hostService; @GetMapping("/getHostMessage/{id}") public JSONObject getHostMessage(@PathVariable String id) { return hostService.getHostMessage(id); } }
7. FeignStarter.java
package com.java.feign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; @EnableEurekaClient @SpringBootApplication @EnableFeignClients(basePackages = { "com.java.feign.service" }) @ComponentScan(basePackages = { "com.java.feign" }) public class FeignStarter extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(FeignStarter.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(FeignStarter.class); } }
8. 运行测试
启动 Eureka 服务注册中心,参考 https://www.cnblogs.com/jonban/p/eureka.html
启动 MicroService 微服务, 参考 https://www.cnblogs.com/jonban/p/microservice.html
启动 Feign服务,运行 FeignStarter.java
浏览器输入URL
http://192.168.1.102/getHostMessage/hello
或
http://127.0.0.1/getHostMessage/hello
返回数据如下:
{"hostname":"F6RK2EXYAFARPPS","hostAddress":"192.168.1.102","id":"hello"}
截图如下:
搭建成功,程序正常运行。
下面开始测试异常
关掉微服务提供者 microservice 服务器
浏览器输入URL
http://192.168.1.102/getHostMessage/hello
或
http://127.0.0.1/getHostMessage/hello
返回数据如下:
{"msg":"com.netflix.client.ClientException: Load balancer does not have available server for client: MICROSERVICE","description":"服务异常演习专用!","id":"hello"}
截图如下:
服务异常生效,符合预期结果。
以上是关于关于feign client触发熔断的异常的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud 源码解读之 如何配置好OpenFeign的各种超时时间!
Spring Cloud中HystrixRibbon及Feign的熔断关系
SpringCloud Feign通过FallbackFactory显示异常信息