1、为什么需要Hystrix
①在分布式环境下,服务和服务之间相互调用,无法确保其他服务的可靠性,服务越多可靠性越低,影响当前主流程可靠性。
②调用当前流程时因为其他关联服务,如果出现异常、超时等,影响整个应用的可用性,会导致大量服务崩溃。
而hystrix类似电路中的保险丝,及时切断故障的服务(通过一些策略优化调用流程),通过依赖隔离使其不会相互影响。
2、hystrix是什么以及基本用法
hystrix底层大量使用RxJava,事件源(被观察者)observable、订阅者(观察者)subscriber,ObservableDemo的rxjavaDemo是简单的rxjava,了解hystrix必须了解一下RxJava。
其他概念:hot Obserable 局部 cold Observable 完整。
下面有简单三个类 ObservableDemo、HystrixObservableCommandDemo、HystrixCommandDemo通过代码来辅助我们了解hystrix的基本使用。
通过ObservableDemo的180行以下的伪代码,可以大概了解客户端、服务方和hystrix command之间的关系
hystrix command包裹住调用服务方逻辑,客服端通过调用hystrix command来执行,而hystrix command通过各种策略来解决上面的两个主要问题。
command的实现类有HystrixCommand和HystrixObservableCommand ,分别用于返回单个结果和多个结果。
流程说明:
1:创建一个新的HystrixCommand或者HystrixObservableCommand对象。
2:命令执行,判断以何种方式执行命令
3:是否启用缓存,结果是否被缓存命中,是 返回缓存结果 否 下一步
4:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略
5:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8.
6:执行命令HystrixCommand中的run/HystrixObservableCommand中的construct方式(业务逻辑)
6a:依赖逻辑调用超时或者异常,进入步骤8.
7:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态.
8:getFallback()降级逻辑.
以下三种情况将触发getFallback调用:
(1):run()或者construct出现异常或超时,非HystrixBadRequestException异常
或者指定忽略的异常
(2):熔断器开启
(3):线程池/队列/信号量是否跑满
8a:没有实现getFallback的Command将直接抛出异常
8aa: execute() 抛出异常
8ab: queue() 调用get()时抛出异常
8ac:observe() 订阅的时候通过onError来通知终止请求
8ad:toObserve() 订阅的时候通过onError通知终止请求
8b:fallback降级逻辑调用成功直接返回
8c:降级逻辑调用失败抛出异常
9:返回执行成功结果Observable
package com.zhou.demo.utils;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.functions.Action1;
import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @auther:
* @description:
* @date: 10:26 2018/10/31
*/
public class ObservableDemo {
/**
* 简单的rxjava demo
*/
public static void rxjavaDemo(){
// 创建事件源
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("hello Rxjava");
subscriber.onNext("who am i");
subscriber.onCompleted();
}
});
// 创建订阅者
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println(" Completed subscriber");
}
@Override
public void onError(Throwable throwable) {
System.out.println(" error subscriber");
}
@Override
public void onNext(String s) {
System.out.println("subscriber :" + s);
}
};
//订阅
observable.subscribe(subscriber);
}
/**
* HystrixCommand执行的execute/queue 同步/异步
*
* queue执行的就是toObservable() 返回Future对象
* execute是直接通过Future得到结果
*/
public static void hystrixCommandDemo(String input, int type){
HystrixCommandDemo command = new HystrixCommandDemo(input);
String result = null;
if(type == 1){
result = command.execute(); // this.queue().get();
}else if(type == 2){
Future<String> queue = command.queue(); // this.toObservable().toBlocking().toFuture();
while (!queue.isDone()){
System.out.println("Do other things ...");
}
try {
result = queue.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}else{
result = testObserve(command, type);
}
System.out.println("执行结果:" + result);
}
/**
* 虽然HystrixCommand具备了observe()和toObservable()的功能,但是它的实现有一定的局限性,只能执行一个命令,所以只会有一个结果
* 而Hystrix还提供了HystrixObservableCommand, 通过它实现的命令可以执行多个command
*
*/
public static String testObserve(HystrixCommandDemo command, int type){
/**
* 返回的是Hot Observable,不论 "事件源" 是否有"订阅者",都会在创建后对事件进行发布。
* 所以对于Hot Observable的每一个“订阅者”都有可能从“事件源”的中途开始的,并可能只是看到了整个操作的局部过程
*/
String result = null;
if(type == 3){
Observable<String> observe = command.observe();
observe.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
System.out.println("==============onCompleted");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onNext(String s) {
System.out.println("=========onNext: " + s);
}
});
observe.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("==================call:" + s);
}
});
result = observe.toBlocking().single();
}else if(type == 4){
/**
* Cold Observable在没有 “订阅者” 的时候并不会发布事件,而是进行等待,直到有 “订阅者” 之后才发布事件
* 所以对于Cold Observable的订阅者,它可以保证从一开始看到整个操作的全部过程
*/
Observable<String> observable = command.toObservable();
System.out.println("此时的结果:" + result);
observable.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("==================call:" + s);
}
});
result = observable.toBlocking().single();
}
return result;
}
public static void hystrixObservableCommandDemo(String input, int type){
HystrixObservableCommandDemo hystrixObservableCommandDemo = new HystrixObservableCommandDemo(input);
if(type == 1){
Observable<String> observe = hystrixObservableCommandDemo.observe();
Iterator<String> iterator = observe.toBlocking().getIterator();
while(iterator.hasNext()){
System.out.println("hystrixObservableCommand observe : " + iterator.next());
}
}else if(type == 2){
Observable<String> observable = hystrixObservableCommandDemo.toObservable();
Iterator<String> iterator = observable.toBlocking().getIterator();
while(iterator.hasNext()){
System.out.println("hystrixObservableCommand toObserve : " + iterator.next());
}
}
}
public static void main(String[] args) {
hystrixCommandDemo("呵呵呵哒", 3);
//hystrixObservableCommandDemo("呵呵呵哒", 4);
}
}
/**
*
* cloud书中伪代码
* 描述客户端---调用者---hystrix command之间的调用关系
*
*/
//接收者/服务方
class Receiver{
public void action(){
}
}
//抽象命令
interface Command{
void execute();
}
//具体命令实现类
class ConcreteCommand implements Command{
private Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
@Override
public void execute() {
this.receiver.action();
}
}
//客户端调用
class Invoker{
private Command command;
public void setCommand(Command command){
this.command = command;
}
public void action(){
command.execute();
}
}
class Client{
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
package com.zhou.demo.utils;
import com.netflix.hystrix.*;
/**
* @auther:
* @description:
* @date: 16:40 2018/11/1
*/
public class HystrixCommandDemo extends HystrixCommand<String> {
private String input;
/**
* GroupKey:该命令属于哪一个组,可以帮助我们更好的组织命令。
CommandKey:该命令的名称
ThreadPoolKey:该命令所属线程池的名称,同样配置的命令会共享同一线程池,若不配置,会默认使用GroupKey作为线程池名称。
CommandProperties:该命令的一些设置,包括断路器的配置,隔离策略,降级设置,以及一些监控指标等。
ThreadPoolProerties:关于线程池的配置,包括线程池大小,排队队列的大小等。
*/
protected HystrixCommandDemo(String input) {
//设置HystrixCommand的属性
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HystrixCommandDemoGroup"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HystrixCommandDemoPool"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10))
);
this.input = input;
}
@Override
protected String run() throws Exception {
return "接收请求:" + input;
}
//服务降级
@Override
protected String getFallback() {
return "exeucute Falled";
}
}
package com.zhou.demo.utils;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixObservableCommand;
import rx.Observable;
import rx.Subscriber;
import rx.schedulers.Schedulers;
/**
* @auther:
* @description:
* @date: 19:05 2018/11/1
*/
public class HystrixObservableCommandDemo extends HystrixObservableCommand<String> {
private String input;
protected HystrixObservableCommandDemo(String input) {
super(HystrixCommandGroupKey.Factory.asKey("HystrixObservableCommandDemoGroup"));
this.input = input;
}
/**
* HystrixObservable通过实现 protected Observable<String> construct() 方法来执行逻辑。
* 通过 重写 resumeWithFallback方法来实现服务降级
*/
@Override
protected Observable construct() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
if(!subscriber.isUnsubscribed()) {
subscriber.onNext("Hello world ");
//int i = 1 / 0; //模拟异常
subscriber.onNext("输入了啥:" + input);
subscriber.onCompleted();
}
} catch (Exception e) {
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.io());
}
/**
* 服务降级
*/
@Override
protected Observable<String> resumeWithFallback() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext("为什么就到fallback了!");
subscriber.onNext("找出异常,找出异常!");
subscriber.onCompleted();
}
} catch (Exception e) {
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.io());
}
}
3、hystrix以及spingCloud
相关架包说明
//org.springframework.cloud:sping-cloud-commons 包含了@SpringCloudApplication @EnableCircuitBreaker、@DiscoveryClient、@LoadBalanced注解等注解
//org.springframework.cloud:spring-cloud-netfix-core 包含@EnableHystrix @FeignClient相关→ribbonFeign相关 ribbon、zuul、metrics、endpoint、archaius、rx(rxJava)
//com.netflix.hystrix:hystrix-core hystrix 核心包
//com.netflix.hystrix:hystrix-javanica hystrix辅助包,包含hystrix相关注解,使用hystrix更方便
我用的版本是1.5.8
zuul是默认开启hystrix的、@EnableZuulProxy中包含@EnableCircuitBreaker
其他服务需要加上hystrix相关依赖和@EnableCircuitBreaker开启hystrix服务
@SpringCloudApplication包含@SpringBootApplication@EnableDiscoveryClient
@EnableCircuitBreaker三个注解
参考:https://github.com/Netflix/Hystrix/wiki
参考:《SpringCloud微服务实战》,电子工业出版社,翟永超