您现在的位置是:亿华云 > 域名
Spring Cloud 中断路器 Circuit Breaker 的应用
亿华云2025-10-08 23:08:19【域名】0人已围观
简介环境:Springboot2.3.12.RELEASE +cloud-netflix-hystrix2.2.10.RELEASE简介SpringCloud Circuit breaker(断路器)提供
环境:Springboot2.3.12.RELEASE +
cloud-netflix-hystrix2.2.10.RELEASE
简介
SpringCloud Circuit breaker(断路器)提供了跨不同断路器实现的断路抽象。它提供了在应用程序中使用的应用一致API,允许开发人员选择最适合应用程序需要的断路断路器实现。
支持的应用断路器类型:
Netfix Hystrix Resilience4J Sentinel Spring Retry核心概念
要在代码中创建断路器(circuit breaker),可以使用断路器工厂API。断路当您在类路径中包含Spring Cloud Circuit Breaker starter时,应用将自动创建一个实现此API的断路bean。下面给出了使用此API的应用一个非常简单的示例:
@Service public static class DemoService { private RestTemplate rest; private CircuitBreakerFactory cbFactory; public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) { this.rest = rest; this.cbFactory = cbFactory; } public String slow() { // 通过默认的CircuitBreakerFactory工厂创建一个指定id(名称)的断路器 // run方法是实际执行你的业务方法,第二个参数throwable 是断路当发生异常或者是执行超时 // 执行的回退(降级)处理 return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback"); } }项目配置
通过引入下面不同依赖来确定使用具体的那个断路器:
Hystrix - org.springframework.cloud:spring-cloud-starter-netflix-hystrix Resilience4J - org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j Reactive Resilience4J - org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j Spring Retry - org.springframework.cloud:spring-cloud-starter-circuitbreaker-spring-retry Sentinal - org.springframework.cloud:spring-cloud-starter-circuitbreaker-sentinal以上5种断路器是不同的实现方式,根据需要引入即可。应用
示例
这里以Hystrix为例来使用
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.10.RELEASE</version> </dependency>定义具有熔断功能的断路服务
@Service public class DemoService { private RestTemplate rest; // 注入系统默认的实现 private CircuitBreakerFactory cbFactory; public DemoService(RestTemplate rest, CircuitBreakerFactory cbFactory) { this.rest = rest; this.cbFactory = cbFactory; } public String slow() { // 使用系统默认的实现创建断路器进行业务的源码下载处理 return cbFactory.create("slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback"); } public String slow2() { // 使用自定义的断路器工厂进行业务的处理 return cbf().create("demo-slow").run(() -> rest.getForObject("http://localhost:8080/demos/slow", String.class), throwable -> "fallback"); } // 可以将这个定义为Bean来覆盖系统默认的实现,在系统默认的应用实现上有条件限定 private CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> cbf() { HystrixCircuitBreakerFactory cbf = new HystrixCircuitBreakerFactory() ; // 配置线程池 HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter() ; threadPoolProperties.withCoreSize(5) .withKeepAliveTimeMinutes(5) .withMaxQueueSize(Integer.MAX_VALUE) .withQueueSizeRejectionThreshold(1000) ; // 配置默认的执行行为属性 HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() ; commandProperties.withCircuitBreakerEnabled(true) // 当请求超过了3s那么断路器就会工作进行回退(降级处理),执行上面run方法中的断路第二个参数 .withExecutionTimeoutInMilliseconds(3000) .withRequestCacheEnabled(true) // 隔离策略有两种THREAD,SEMAPHORE // THREAD: 避免线程被阻塞 // SEMAPHORE: 适合高并发限流处理;因为线程池的应用方式一般不会创建过多的线程 // 线程是有限的,在高并发情况下是断路没法满足响应处理的。 .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD); // 将其加入到集合中,为不同的服务创建不同的配置 cbf.configure(builder -> { builder.commandProperties(commandProperties).groupName("demo") ; }, "demo-slow"); // 当默认的id不存在时使用这默认的配置 cbf.configureDefault(id -> { HystrixCommand.Setter setter = HystrixCommand.Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey("demo")) // 服务分组,大的模块 .andCommandKey(HystrixCommandKey.Factory.asKey("demo-slow")) // 服务标识(具体服务分组中的某一个子的服务),子模块 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("demo-pools")) // 线程池名称 .andThreadPoolPropertiesDefaults(threadPoolProperties) // 线程池相关配置 .andCommandPropertiesDefaults(commandProperties) ; // 执行时相关属性配置 return setter ; }); return cbf ; } }Controller接口
@RestController @RequestMapping("/demos") public class DemoController { @Resource private DemoService demoService ; @GetMapping("/index") public Object index() { return demoService.slow2() ; } @GetMapping("/slow") public Object slow() { try { TimeUnit.SECONDS.sleep(5) ; } catch (InterruptedException e) { e.printStackTrace(); } return "slow" ; } }原理
CircuitBreakerFactory#create方法创建了CircuitBreaker实例。
根据当前的CLASSPATH我们使用的站群服务器是Hystrix,那么这里使用的工厂就是:
HystrixCircuitBreakerFactory类
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> {泛型参数:Setter就是用来配置Hystrix相关配置信息的(这里主要用来CommandKey与Setter进行绑定),HystrixConfigBuilder用来构建 HystrixCommand.Setter对象。
当执行HystrixCircuitBreakerFactory#configure方法时:
public abstract class AbstractCircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>> { private final ConcurrentHashMap<String, CONF> configurations = new ConcurrentHashMap<>(); public void configure(Consumer<CONFB> consumer, String... ids) { for (String id : ids) { // 构建一个Builder对象 CONFB builder = configBuilder(id); // 这里通过builder(HystrixConfigBuilder)对象来应用Consumer中编写的配置信息 consumer.accept(builder); // 构建HystrixCommand.Setter 对象 CONF conf = builder.build(); // 最后将通过id 与 Setter对象绑定key=value存入Map集合中 getConfigurations().put(id, conf); } } // 该方法在子类HystrixCircuitBreakerFactory中实现 protected abstract CONFB configBuilder(String id); }断路器具体的子类实现
HystrixCircuitBreakerFactory
// 子类继承的父类中的泛型:第一个泛型参数:需要构建什么样的一个配置,第二个泛型参数:通过谁来构建第一个泛型参数配置 public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> { public HystrixConfigBuilder configBuilder(String id) { return new HystrixConfigBuilder(id); } public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder<HystrixCommand.Setter> { public HystrixConfigBuilder(String id) { super(id); } // 从这里也看出来最终Builder就是用来构建Setter对象用 @Override public HystrixCommand.Setter build() { return HystrixCommand.Setter.withGroupKey(getGroupKey()) .andCommandKey(getCommandKey()) .andCommandPropertiesDefaults(getCommandPropertiesSetter()); } } }断路器工厂有了,接下来就是通过工厂创建具体的断路器对象了。
通过上面的代码执行cbf().create("demo-slow")方法时执行了什么?
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory<HystrixCommand.Setter, HystrixCircuitBreakerFactory.HystrixConfigBuilder> { private Function<String, HystrixCommand.Setter> defaultConfiguration = id -> HystrixCommand.Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName())) .andCommandKey(HystrixCommandKey.Factory.asKey(id)); public HystrixCircuitBreaker create(String id) { // 通过上面分析最终所有的Hystrix的Setter会与id绑定存入一个Map中 // 这里computeIfAbsent方法先从集合中通过id获取,如果获取不到则将第二个参数存入集合中返回 HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id, defaultConfiguration); return new HystrixCircuitBreaker(setter); } }上面创建的是HystrixCircuitBreaker断路器,当执行run方法时:
public class HystrixCircuitBreaker implements CircuitBreaker { private HystrixCommand.Setter setter; public HystrixCircuitBreaker(HystrixCommand.Setter setter) { this.setter = setter; } @Override public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) { // 最终执行的就是Hystrix的核心 HystrixCommand对象 HystrixCommand<T> command = new HystrixCommand<T>(setter) { @Override protected T run() throws Exception { return toRun.get(); } @Override protected T getFallback() { return fallback.apply(getExecutionException()); } }; return command.execute(); } } 免费信息发布网很赞哦!(9594)
相关文章
- 只要我们做的是从目前的市场情况选择域名,从简单易记,从个性特征上,我们就可以找到一个好域名进行注册。域名注册进行域名记录和解析以及绑定网站后,客户可以通过URL登录您的网站。
- 一口价域名出售有什么优势?
- 域名能查到从哪里购买的吗?
- 域名注册成功后怎么使用网站?
- 域名不仅仅是一个简单的网站。对于有长远眼光的公司来说,在运营网站之前确定一个优秀的域名对有长远眼光的公司来说是非常重要的。这对今后的市场营销、产品营销和企业品牌建设都具有十分重要的意义。优秀的域名是企业在市场竞争中获得持久优势的利器。
- GO 实现高并发高可用分布式系统:Log微服务的实现
- 通过强化客户关系和.icu域名扩展提升小型企业的成功
- 再聊一下那SQL Server 行不能跨页的事
- a、变更前的公司证件扫描件(代码证或者营业执照)及联系人身份证复印件、变更后的公司证件扫描件(代码证或者营业执照)及新的联系人身份证复印件;身份证复印件需本人签名,公司证件复印件需加盖公章。
- 爆爆:Java代码编译流程是怎样的?
热门文章
站长推荐
为了避免将来给我们的个人站长带来的麻烦,在选择域名后缀时,我们的站长最好省略不稳定的后缀域名,比如n,因为我们不知道策略什么时候会改变,更不用说我们将来是否还能控制这个域名了。因此,如果站长不是企业,或者有选择的话,如果不能选择域名的cn类,最好不要选择它。
.Ltd与.group域名助力企业与团体网络品牌建设
面试突击:说一下HashMap底层实现?及元素添加流程?
新来个技术总监:谁在用isXxx形式定义布尔类型年后不用来了
2、根据用户基础选择访问提供程序。由于互联问题的存在,接入商的选择也非常重要,如果用户群主要在联通,尽量选择联通接入较好的接入商,如果用户群主要在电信,那么选择电信接入较好的接入商。如果用户组位于国家/地区,则选择更好的访问提供程序进行交互。
写点规范的 Go 代码,你学会了吗?
Linux安装MariaDB数据库的实例详解
清除SQL Server数据库日志(ldf文件)的方法汇总