参考
- https://blog.csdn.net/zhangchaoyang/article/details/123453616
- https://blog.csdn.net/u010277958/article/details/88744263
- https://blog.csdn.net/iwlnner/article/details/110090595
- https://cloud.tencent.com/developer/article/2225692
- https://blog.csdn.net/zhuocailing3390/article/details/123215227
- https://www.cnblogs.com/fuxuepan/p/12012195.html
- https://blog.csdn.net/east123321/article/details/82385816
- https://www.cnblogs.com/liconglong/p/15408858.html
- https://www.cnblogs.com/liconglong/p/15408858.html
- 本文代码 下载
踩坑与注意
- OpenFeign 默认超时为 1s,如果使用 Hystrix 的时候,报以下错误,可以尝试修改 OpenFeign 超时时间。
- Read timed out executing GET
- 配置 Hystrix HystrixTimeoutException 超时 不生效
- Hystrix circuit short-circuited and is OPEN (因为失败过多,自动触发短路)
- 找不到
@HystrixCommand
相关注解,因为spring-cloud-starter-openfeign
依赖虽然集成了 Hystrix ,但是并没有相关注解,需要引入spring-cloud-starter-netflix-hystrix
依赖。 - 测试 Ribbon 超时配置并未生效(环境:消费者和注册中心在线,提供者下线;Feign 超时设置100s,Ribbon 设置2s)。
- 参考 jeecg-boot 服务降级是将所有远程调用接口封装到一个类,然后使用 fallbackFactory 模式进行处理。
- Ribbon 已被
spring-cloud-starter-openfeign
集成。 - Hystrix 可以有很多方式指定降级处理函数。
- 可以通过 Hystrix Dashboard 进行监控和调试。
环境
环境 | 版本 | 说明 |
---|---|---|
windows | 10 | |
vs code | 1.85.1 | |
Spring Boot Extension Pack | v0.2.1 | vscode插件 |
Extension Pack for Java | v0.25.15 | vscode插件 |
JDK | 11 | |
Springboot | 2.3.12.RELEASE | |
spring-cloud-dependencies | Hoxton.SR12 | mvn依赖 |
spring-cloud-starter-netflix-eureka-client | 未设置 | mvn依赖 |
spring-cloud-starter-netflix-eureka-server | 未设置 | mvn依赖 |
spring-cloud-starter-openfeign | 未设置 | mvn依赖 |
spring-cloud-starter-netflix-hystrix | 未设置 | mvn依赖,如果不需要 hystrix 相关注解可以不引入,可以通过 @FeignClient 注解 fallbackFactory、fallback 进行指定降级处理类。 |
Apache Maven | 3.8.6 |
正文
项目分为多模块:注册中心(registry)、消费者(consumer)、提供者(provider)、common (公共模块)。
准备工作
准备工作请参考该文章实现基础项目的搭建 《Spring Boot2.x 集成 Eureka 与 OpenFeign》,本文代码可通过文章顶部 参考 中下载。
application.properties
修改默认超时与开启 hystrix。
# feign开启hystrix
feign.circuitbreaker.enabled=true
# 修改超时时间
feign.client.config.default.connectTimeout=100000
feign.client.config.default.readTimeout=600000
# # 配置所有服务连接超时
# feign.client.config.default.connect-timeout=5000
# #配置所有服务等待超时
# feign.client.config.default.read-timeout=5000
# 日志
feign.client.config.default.loggerLevel=full
# gzip压缩
feign.compression.request.enabled=true
feign.compression.response.enabled=true
# hystrix
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
# hystrix.command.default.metrics.rollingStats.timeInMilliseconds=5000
# hystrix.command.default.circuitBreaker.requestVolumeThreshold=4
# hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
# hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=3000
# hystrix.command.commandKeyTest.execution.isolation.thread.timeoutInMilliseconds=10000
Hystrix 熔断降级 (消费者(consumer)子模块)
由于本文没有使用到 hystrix 的相关注解,直接使用 @FeignClient 注解 fallbackFactory、fallback 进行指定降级处理类进行演示。如果需要 hystrix 的相关注解,请 pom.xml 引入
spring-cloud-starter-netflix-hystrix
依赖。
fallbackFactory 类重写 create ,返回的是当前接口的实例;fallback 实现的是当前接口;
参考 jeecg-boot 如果调用的 Feign 接口函数包含返回值,则返回 null,然后在调用处代码判断是否是 null。
-
入口文件
package com.xiaqiuchu.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients @EnableEurekaClient @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
-
fallbackFactory 模式(推荐,可以获取报错信息,与 fallback 模式任选其一)。
- StudentService
package com.xiaqiuchu.consumer.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.xiaqiuchu.common.entity.Student; import com.xiaqiuchu.consumer.component.StudentServiceFallBackFactory; // 回退类正常模式(无法获取详细报错信息) // @FeignClient(value = "STUDENT-TEACHER-PROVIDER", fallback = StudentServiceFallBack.class) // 工厂模式(获取详细报错信息) @FeignClient(value = "STUDENT-TEACHER-PROVIDER", fallbackFactory = StudentServiceFallBackFactory.class) public interface StudentService { @RequestMapping(method = RequestMethod.GET, value = "/student/findById") public Student findById(@RequestParam(name = "id") Long id); @RequestMapping(method = RequestMethod.GET, value = "/student/ping") public String ping(); }
- StudentServiceFallBackFactory
package com.xiaqiuchu.consumer.component; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.stereotype.Component; import com.xiaqiuchu.common.entity.Student; import com.xiaqiuchu.consumer.service.StudentService; import lombok.extern.slf4j.Slf4j; // https://blog.csdn.net/weixin_42771651/article/details/121626431 // https://blog.csdn.net/qq_41125219/article/details/121346640 @Slf4j @Component public class StudentServiceFallBackFactory implements FallbackFactory<StudentService>{ @Override public StudentService create(Throwable cause) { log.error("远程调用出错,异常原因:{}", cause.getMessage(), cause); return new StudentService(){ @Override public Student findById(Long id) { return new Student(); } @Override public String ping() { return "err"; } }; } }
- StudentService
-
fallback 模式(与 fallbackFactory 模式任选其一)。
- StudentService
package com.xiaqiuchu.consumer.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.xiaqiuchu.common.entity.Student; import com.xiaqiuchu.consumer.component.StudentServiceFallBack; import com.xiaqiuchu.consumer.component.StudentServiceFallBackFactory; // 回退类正常模式(无法获取详细报错信息) @FeignClient(value = "STUDENT-TEACHER-PROVIDER", fallback = StudentServiceFallBack.class) // 工厂模式(获取详细报错信息) // @FeignClient(value = "STUDENT-TEACHER-PROVIDER", fallbackFactory = StudentServiceFallBackFactory.class) public interface StudentService { @RequestMapping(method = RequestMethod.GET, value = "/student/findById") public Student findById(@RequestParam(name = "id") Long id); @RequestMapping(method = RequestMethod.GET, value = "/student/ping") public String ping(); }
- StudentServiceFallBack
package com.xiaqiuchu.consumer.component; import org.springframework.stereotype.Component; import com.xiaqiuchu.common.entity.Student; import com.xiaqiuchu.consumer.service.StudentService; /** * 回退类实现 */ @Component public class StudentServiceFallBack implements StudentService { // public StudentServiceFallBack(){ // } @Override public Student findById(Long id) { return new Student(); // TODO Auto-generated method stub // throw new UnsupportedOperationException("Unimplemented method 'findById'"); } @Override public String ping() { // TODO Auto-generated method stub // throw new UnsupportedOperationException("Unimplemented method 'ping'"); return "error"; } }
- StudentService
Ribbon 负载均衡 (消费者(consumer)子模块)
负载均衡模式有很多种,轮询策略、随机策略、重试策略、最可用策略、可用过滤算法、自定义处理等。
- 新建
FeignConfiguration.java
。package com.xiaqiuchu.consumer.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; /** * https://www.cnblogs.com/liconglong/p/15408858.html */ @Configuration public class FeignConfiguration { /** * 配置随机的负载均衡策略 * 特点:对所有的服务都生效 */ @Bean public IRule loadBalancedRule() { return new RandomRule(); } }