服务容错保护 Spring Cloud Hystrix
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
@EnableCircuitBreaker注解与@SpringCloudApplication
//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication
@SpringCloudApplication
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class,args);
}
}
指定回调方法
@Service
public class UserService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "defaultSec")
private String defaultUser(){
return restTemplate.getForObject("http://user-server/users/{1}",User.class,id);
}
public String defaultSec(){
return "error";
}
}
1.原理-工作流程
(1)创建HystruxCommand或HystrixObservableComand对象
命令模式
(2)命令执行
RxJava观察者订阅者模式
private void RxJava(){
// 创建事件源observable
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello RxJava");
subscriber.onNext("Im 程序员 haha");
subscriber.onCompleted();
}
});
// 创建订阅者
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
System.out.println("subscriber:" + s);
}
};
// 订阅
observable.subscribe(subscriber);
}
(3)结果是否被缓存
(4)断路器是否断开
(5)线程池、请求队列、信号量是否占满
(6)HystrixObservableComand.construct()或Hystrix.run()
(7)计算断路器健康度
(8)fallback处理
服务降级:当命令执行失败的时候,Hystrix会进入fallback尝试回退处理
(9)返回成功的响应
2.断路器原理
public interface HystrixCircuitBreaker {
boolean allowRequest();
boolean isOpen();
void markSuccess();
public static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
// ...
}
public static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
// ...
}
public static class Factory {
// ...
}
}
allowRequest():每个Hystrix命令的请求都通过它判断是否被执行
public boolean allowRequest() {
// 配置文件断路器判断强制打开或关闭属性
if ((Boolean)this.properties.circuitBreakerForceOpen().get()) { // 强制打开
return false;
} else if ((Boolean)this.properties.circuitBreakerForceClosed().get()) { // 强制关闭
this.isOpen();
return true;
} else {
// 判断请求是否被允许
return !this.isOpen() || this.allowSingleTest();
}
}
通过设置休眠时间,allowSingleTest()方法,在断路器打开设置的时间(默认5秒),休眠时间到达之后再次请求尝试访问,处于”半开“状态,请求成功,则断路器关闭,请求失败,则继续打开。
public boolean allowSingleTest() {
long timeCircuitOpenedOrWasLastTested = this.circuitOpenedOrLastTestedTime.get();
return this.circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + (long)(Integer)this.properties.circuitBreakerSleepWindowInMilliseconds().get() && this.circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis());
}
isOpen():返回当前断路器是否打开
public boolean isOpen() {
if (this.circuitOpen.get()) {
return true;
} else {
HealthCounts health = this.metrics.getHealthCounts();
if (health.getTotalRequests() < (long)(Integer)this.properties.circuitBreakerRequestVolumeThreshold().get()) {
return false;
} else if (health.getErrorPercentage() < (Integer)this.properties.circuitBreakerErrorThresholdPercentage().get()) {
return false;
} else if (this.circuitOpen.compareAndSet(false, true)) {
this.circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
return true;
}
}
}
markSuccess():用来闭合断路器
public void markSuccess() {
if (this.circuitOpen.get() && this.circuitOpen.compareAndSet(true, false)) {
this.metrics.resetStream();
}
}
该函数在“半开路”时候使用,若Hystrix命令调用成功,调用此方法关闭断路器,重置度量指标对象。
3.依赖隔离
舱壁模式
Hystrix使用舱壁模式实现线程池的隔离,它会为每一个依赖服务创建独立的线程池。自身完全保护,有效降低新服务风险,快速查找解决问题,不停服务解决,应用更加灵活
Hystrix信号量:控制单个依赖服务并发度