评论

收藏

[Java] Spring Cloud 中断路器 Circuit Breaker的应用

编程语言 编程语言 发布于:2021-12-16 11:36 | 阅读数:618 | 评论:0

SpringCloud Circuit breaker(断路器)提供了跨不同断路器实现的抽象。它提供了在应用程序中使用的一致API,允许开发人员选择最适合应用程序需要的断路器实现。
DSC0000.png

环境: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为例来使用
引入依赖

org.springframework.cloud 
spring-cloud-starter-netflix-hystrix 
2.2.10.RELEASE
定义具有熔断功能的服务
@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 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 {
泛型参数:Setter就是用来配置Hystrix相关配置信息的(这里主要用来CommandKey与Setter进行绑定),HystrixConfigBuilder用来构建 HystrixCommand.Setter对象。
当执行HystrixCircuitBreakerFactory#configure方法时:
public abstract class AbstractCircuitBreakerFactory
断路器具体的子类实现HystrixCircuitBreakerFactory
// 子类继承的父类中的泛型:第一个泛型参数:需要构建什么样的一个配置,第二个泛型参数:通过谁来构建第一个泛型参数配置 
public class HystrixCircuitBreakerFactory extends CircuitBreakerFactory { 
public HystrixConfigBuilder configBuilder(String id) { 
return new HystrixConfigBuilder(id); 
} 
public static class HystrixConfigBuilder extends AbstractHystrixConfigBuilder { 
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 { 
private Function 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 run(Supplier toRun, Function fallback) { 
// 最终执行的就是Hystrix的核心 HystrixCommand对象 
HystrixCommand command = new HystrixCommand(setter) { 
@Override 
protected T run() throws Exception { 
return toRun.get(); 
} 
@Override 
protected T getFallback() { 
return fallback.apply(getExecutionException()); 
} 
}; 
return command.execute(); 
} 
}
原文链接:https://www.toutiao.com/a7036197230167982630/

关注下面的标签,发现更多相似文章