我们耳熟能详的就是Netflix Hystrix,这个断路器是SpringCloud中最早支持的一种容错方案,现在这个断路器已经处于维护状态,已经不再更新了。Hystrix官方推荐使用Resilience4j。
关于Netflix为什么会宣布停止在开源版本上提供新功能,目前官方并没有给出原因,只是提供了一些解决方案。但我看到Netflix官方博客的一篇文章,也许能找到技术层面的考量:Netflix 现在正在探索更自动化的熔断方式。所以我们猜测Netflix内部会逐步不再使用Hystrix ,没有继续更新的动力;再加上 Hystrix 作为一个熔断降级组件已经非常稳定了,因此停止开发是可以理解的。另一个是非技术层面,技术的开源是需要业务的增长和完整的技术团队来支撑的,无论是国内还是国外,开源项目能否持续,依赖于企业在技术上是否能长期投入。通知原文地址
现在还有阿里开发的sentinel 也可以作为熔断器
功能对比:
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发控制) | 线程池隔离/信号量隔离 |
信号量隔离 |
熔断降级策略 | 基于慢调用比例、异常比例、异常数 | 基于异常比例 | 基于异常比例、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式与匀速排队控制效果 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
多语言支持 | Java/Go/C++ | Java | Java |
Service Mesh 支持 | 支持 Envoy/Istio | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、实时监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
Sentinel不创建线程依赖tomcat或jetty容器的线程池,存在的问题就是运行容器的线程数量限制了sentinel设置值的上限可能设置不准。比如tomcat线程池为10,sentinel设置100是没有意义的,同时隔离性不好hystrix使用自己创建的线程池,隔离性会更好
例子:使用nacos+sentinel
在https://github.com/alibaba/nacos下载nacos服务
默认地址:http://127.0.0.1:8848/nacos,用户和密码是:nacos
建立项目结构,一个提供者和消费者
在父类pom配置相关版本,本来打算使用最新Hoxton.SR10+com.alibaba.cloud,2.2.5.RELEASE,结果发现出现错误:https://github.com/alibaba/spring-cloud-alibaba/issues/1974
Requested bean is currently in creation: Is there an unresolvable circular reference
看来版本间还是有点问题,就换成了低一点的版本Hoxton.SR9+com.alibaba.cloud,2.2.5.RELEASE
版本之间关系
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
1.父类定义版本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"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>testnacos</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>nacos-provider</module> <module>nacos-consumer</module> </modules> <name>testnacos</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot.version>2.3.2.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> <spring-cloud.Alibaba.version>2.2.5.RELEASE</spring-cloud.Alibaba.version> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud.Alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
提供者nacos-provider
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>testnacos</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>nacos-provider</artifactId> <name>nacos-provider</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies> </project>
提供者的启动类和测试接口
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}
@RestController
class EchoController {
@GetMapping("/echo/{param}")
public String echo(@PathVariable("param") String param) {
return "Hello Nacos Discovery " + param;
}
}
}
配置文件application.properties:
server.port=8070
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
消费者nacos-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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>testnacos</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>nacos-consumer</artifactId> <name>nacos-consumer</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <spring-cloud-openfeign.version>2.2.6.RELEASE</spring-cloud-openfeign.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>${spring-cloud-openfeign.version}</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> </dependencies> </project>
启动类NacosConsumerApplication,打开注册和服务调用注解
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class NacosConsumerApplication { @Autowired private ProviderClient providerClient; public static void main(String[] args) { SpringApplication.run(NacosConsumerApplication.class, args); } @RestController class EchoController { @GetMapping("/echo/{param}") public String echo(@PathVariable("param") String param) { return providerClient.echo(param); } } }
定义远程调用ProviderClient
@FeignClient(value = "service-provider", fallback = ProviderClientFallback.class) //@FeignClient(value="service-provider",fallbackFactory = ProviderClientFallbackFactory.class) public interface ProviderClient { @GetMapping("/echo/{param}") String echo(@PathVariable("param") String param); }
服务失败的回调ProviderClientFallback
@Component public class ProviderClientFallback implements ProviderClient { @Override public String echo(String param) { return "echo-Fallback"; } }
也可以继承FallbackFactory进行回调,这样可以得到异常的信息
@Component public class ProviderClientFallbackFactory implements FallbackFactory<ProviderClient> { @Override public ProviderClient create(Throwable cause) { System.out.println(cause.getMessage()); return new ProviderClient() { @Override public String echo(String param) { return "FallbackFactory-echo"; } }; } }
设置application.properties打开Sentinel
server.port=8081 spring.application.name=service-consumer spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 feign.sentinel.enabled=true #feign.hystrix.enabled=true
整体项目结构
先启动消费服务nacos-consumer,然后在nacos服务中心观察注册情况
发现已经注册到服务中心了,然后调用接口
观察到执行到熔断的结果了,然后在运行提供服务nacos-provider。并观察nacos服务中心
发现已经也注册到服务中心了,等待一段时间后在调用测试接口(因为消费者客户端定时会想服务中心查询服务列表)
发现成功调用接口
参考
https://developer.aliyun.com/article/633786
https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel
https://www.sohu.com/a/282806665_268033
https://www.cnblogs.com/zhyg/p/11474406.html