SpringBoot升级后Hystrix没了以及3个替代方案分享
作者:真实的菜
写在前面
公司项目要从 Spring Boot 2.2.x 升级到 2.7,领导让我负责调研。
拿到手一看,好家伙,Hystrix 停更了?Feign 的 fallback 怎么报错了?Ribbon 也不推荐用了?
网上的文档要么太深奥,要么太简单。没办法,只能自己一点点啃,顺便把踩坑经历记下来。
如果你也是新手,希望这篇笔记能帮到你。
环境信息
- Spring Boot: 2.2.x → 2.7.18
- Spring Cloud: Hoxton.SR9 → 2021.x
- Hystrix: 1.5.x(停更)→ Resilience4j 1.7.x
- Ribbon: 2.x(停更)→ Spring Cloud LoadBalancer
- OpenFeign: 2.2.x → 3.1.x
坑 1:Hystrix 停更了,用啥替代?
我当时以为很简单
直接升级 Spring Boot 和 Spring Cloud,心想依赖会自动更新…
<!-- 我当时看到这个配置,心想这不简单吗 --> <spring-boot.version>2.7.18</spring-boot.version> <spring-cloud.version>2021.x</spring-cloud.version>
结果启动失败:
*************************** APPLICATION FAILED TO RUN *************************** Description: The Spring Cloud project contains incompatible modules: spring-cloud-starter-netflix-hystrix is not compatible with Spring Cloud 2021.x and later.
我当时就懵了。啥?Hystrix 不兼容?
问题根源
后来查资料才明白:
- Hystrix 停更:Netflix Hystrix 从 2020 年开始就进入维护模式,不再更新
- Spring Cloud 移除:Spring Cloud 2020.x(Illford)开始移除了对 Hystrix 的支持
- 官方推荐:Spring 官方推荐使用 Resilience4j 作为替代方案
好家伙,原来是时代的眼泪。
解决方案
用 Resilience4j 替代 Hystrix
<!-- 移除 Hystrix 依赖 -->
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
-->
<!-- 添加 Resilience4j 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>配置 Resilience4j:
# application.yml
resilience4j:
circuitbreaker:
instances:
backendA: # 服务名
registerHealthIndicator: true
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 10000
permittedNumberOfCallsInHalfOpenState: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
timeout:
timeout: 3s
cancelRunningFuture: false使用方式:
@Service
public class MyService {
@CircuitBreaker(name = "backendA", fallbackMethod = "fallback")
public String callExternalService() {
// 调用外部服务
return "success";
}
// fallback 方法
public String fallback(Exception e) {
log.error("服务调用失败,执行 fallback: {}", e.getMessage());
return "fallback result";
}
}
教训:Hystrix 已经停更了,别再用!官方推荐 Resilience4j!
坑 2:Feign 的 FallbackFactory 报错了
我只排除了部分依赖
升级后,Feign Client 的 fallback 全部报错:
// 原来的代码
@FeignClient(name = "soa-protocol-control",
fallbackFactory = ControlVehicleFeignServiceFallback.class)
public interface ControlVehicleFeignService {
// ...
}
启动报错:
java.lang.IllegalStateException: FallbackFactory must return an instance of the FeignClient interface
我当时又懵了。这又是啥?
原因分析
后来才明白:
- Hystrix 移除:
feign.hystrix.FallbackFactory是 Hystrix 时代的产物 - 包路径变更:Spring Cloud 2021.x 开始,FallbackFactory 的包路径变了
- 返回值要求:fallback 必须返回 FeignClient 接口的实例
正确做法
1. 修改导入包
// ❌ 原来的导入(Hystrix 时代) import feign.hystrix.FallbackFactory; // ✅ 现在的导入(Resilience4j 时代) import org.springframework.cloud.openfeign.FallbackFactory;
2. 实现 FallbackFactory
@Slf4j
@Component
public class ControlVehicleFeignServiceFallbackFactory
implements FallbackFactory<ControlVehicleFeignService> {
@Override
public ControlVehicleFeignService create(Throwable cause) {
log.error("---控车接口回退异常:{}", cause);
return new ControlVehicleFeignService() {
@Override
public BaseResponseVo<Long> executeInstruct(UserControlVehicleDTO dto) {
return BaseResponseVo.fail(PROTOCOL_CONTROL_ERROR);
}
@Override
public BaseResponseVo<Long> selectCurrentRideUserIdByVin(String vin) {
return BaseResponseVo.fail(PROTOCOL_CONTROL_ERROR);
}
// ... 其他方法都返回 fallback 结果
};
}
}
3. 使用 FallbackFactory
@FeignClient(
name = "soa-protocol-control",
contextId = "userControlVehicle",
fallbackFactory = ControlVehicleFeignServiceFallbackFactory.class // 注意是 fallbackFactory
)
public interface ControlVehicleFeignService {
@PostMapping("/protocol-control/user/control/vehicle")
BaseResponseVo<Long> executeInstruct(@RequestBody UserControlVehicleDTO dto);
@GetMapping("/protocol-control/current/ride-user-id")
BaseResponseVo<Long> selectCurrentRideUserIdByVin(@RequestParam String vin);
// ... 其他接口
}
教训:FallbackFactory 的包路径变了,别用错导入!
坑 3:Ribbon 也不推荐用了?
我以为禁用就完事了
升级后发现 Ribbon 也停更了,启动时各种警告:
WARN: Ribbon is now in maintenance mode.
Consider using Spring Cloud LoadBalancer instead.
这又是啥?
原因分析
后来才明白:
- Ribbon 停更:Netflix Ribbon 也进入维护模式
- 官方推荐:Spring Cloud LoadBalancer 作为替代
- 配置变更:LoadBalancer 的配置方式和 Ribbon 不一样
正确做法
1. 添加依赖
<!-- Spring Cloud LoadBalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>2. 配置 LoadBalancer
# application.yml
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # 禁用 Ribbon
cache:
ttl: 30000 # 缓存过期时间(毫秒)
capacity: 256 # 缓存容量3. 自定义负载均衡策略
@Configuration
public class LoadBalancerConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
LoadBalancerClientFactory clientFactory) {
return new RandomLoadBalancer(
clientFactory.getLazyProvider("service-name", ServiceInstanceListSupplier.class),
"service-name"
);
}
}
4. 使用 LoadBalancer
@Service
public class MyService {
@Autowired
private RestTemplate restTemplate;
public String callService(String data) {
// 使用服务名调用,LoadBalancer 会自动做负载均衡
String url = "http://service-name/api/" + data;
return restTemplate.getForObject(url, String.class);
}
}
教训:Ribbon 已经停更了,赶紧换成 LoadBalancer!
配置对比(Hoxton vs 2021.x)
Hoxton 配置(自动配置)
// 啥都不用配,Hystrix 自动帮你搞定
@EnableHystrix
@EnableFeignClients
@SpringBootApplication
public class Application {
// ...
}
好处:简单,省事
坏处:
- Hystrix 停更了
- 性能不如 Resilience4j
- 配置不灵活
2021.x 配置(手动配置)
// 启用 Resilience4j + OpenFeign + LoadBalancer
@EnableFeignClients
@SpringBootApplication
public class Application {
// ...
}
// Resilience4j 配置
@Configuration
public class Resilience4jConfig {
@Bean
public CircuitBreakerConfig circuitBreakerConfig() {
return CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.slidingWindowSize(10)
.build();
}
}
好处:
- 官方推荐,持续更新
- 性能更好
- 配置更灵活
坏处:配置多了点
我的感受:
- 虽然配置多了,但心里有底
- Resilience4j 的 API 更现代
- 出了问题知道从哪查
- 推荐大家都这么配(虽然麻烦点)
Fallback 和 FallbackFactory 的区别
Fallback:简单场景
适用场景:只需要返回默认值
@FeignClient(
name = "user-service",
fallback = UserFeignClientFallback.class // 直接返回实例
)
public interface UserFeignClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable Long id);
}
@Component
public class UserFeignClientFallback implements UserFeignClient {
@Override
public User getUser(Long id) {
return new User(0L, "default", "default@example.com");
}
}
好处:简单,代码少
坏处:拿不到异常信息
FallbackFactory:复杂场景(推荐)
适用场景:需要记录异常日志、根据异常类型做不同处理
@FeignClient(
name = "user-service",
fallbackFactory = UserFeignClientFallbackFactory.class // 工厂模式
)
public interface UserFeignClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable Long id);
}
@Slf4j
@Component
public class UserFeignClientFallbackFactory
implements FallbackFactory<UserFeignClient> {
@Override
public UserFeignClient create(Throwable cause) {
log.error("Feign 调用失败:{}", cause.getMessage()); // 可以记录日志
return new UserFeignClient() {
@Override
public User getUser(Long id) {
// 根据异常类型做不同处理
if (cause instanceof ConnectException) {
return new User(0L, "network-error", "连接失败");
} else {
return new User(0L, "unknown-error", "未知错误");
}
}
};
}
}
好处:
- 可以记录异常日志
- 可以根据异常类型做不同处理
- 更灵活
坏处:代码多了点
我的建议:
- 简单场景用 Fallback
- 生产环境推荐用 FallbackFactory(可以记录日志)
验证步骤
1. 检查依赖
# 查看项目依赖树 mvn dependency:tree | Select-String "hystrix|resilience4j|ribbon|loadbalancer"
预期结果:
- 不应该有
spring-cloud-starter-netflix-hystrix - 应该有
spring-cloud-starter-circuitbreaker-resilience4j - 不应该有
ribbon - 应该有
spring-cloud-starter-loadbalancer
2. 启动测试
启动应用,确认没有以下警告:
❌ Hystrix is not compatible with Spring Cloud 2021.x ❌ Ribbon is now in maintenance mode
3. 测试 Fallback
// 手动触发异常,测试 fallback 是否生效
@Test
public void testFallback() {
// 模拟服务不可用
String result = feignClient.callService();
assertEquals("fallback result", result);
}
我整理的一些配置
Resilience4j 推荐配置
# 这些是我实测好用的
resilience4j:
circuitbreaker:
instances:
backendA:
registerHealthIndicator: true
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 10000
permittedNumberOfCallsInHalfOpenState: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
timelimiter:
timeoutDuration: 3sLoadBalancer 推荐配置
spring:
cloud:
loadbalancer:
ribbon:
enabled: false
cache:
ttl: 30000
capacity: 256监控指标
# Resilience4j 的监控指标(要加到 Prometheus 里) resilience4j.circuitbreaker.states resilience4j.circuitbreaker.failure.rate resilience4j.circuitbreaker.slow.call.rate
回滚方案
如果升级后出现问题,可以快速回滚:
- 恢复
pom.xml中的 Spring Boot 和 Spring Cloud 版本 - 恢复 Hystrix 依赖
- 恢复 Ribbon 依赖
- 恢复原来的 Fallback 实现
- 重新编译部署
教训:升级前一定要留好退路!
总结
我踩过的坑
- 坑 1:以为 Hystrix 还能用 → 启动报不兼容错误
- 坑 2:FallbackFactory 导入错误 → 报返回值类型错误
- 坑 3:Ribbon 没换成 LoadBalancer → 各种警告
核心要点
- 必须替换 Hystrix:用 Resilience4j,官方推荐
- 必须修改 FallbackFactory 导入:从
feign.hystrix换成org.springframework.cloud.openfeign - 必须替换 Ribbon:用 Spring Cloud LoadBalancer
- 必须测试 fallback:确保服务降级正常工作
最后说两句
其实也没多难,就是配置多了点。
我刚开始也懵,后来一点点试,总算是搞定了。
肯定有理解不对的地方,欢迎大佬指正。
如果你也遇到类似问题,希望这篇笔记能帮到你。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
