Hystrix是Netflix开源的一款容错系统,能帮助使用者码出具备强大的容错能力和鲁棒性的程序。支持降级、熔断、隔离等高可用特效。下面一一介绍。
一、基本用法
将需要封装接口,继承HystrixCommand,并实现run()方法。
HystrixCommand支持4种调用方式。
1、execute():以同步堵塞方式执行run()。以demo为例,调用execute()后,hystrix先创建一个新线程运行run(),接着调用程序要在execute()调用处一直堵塞着,直到run()运行完成
2、queue():以异步非堵塞方式执行run()。以demo为例,一调用queue()就直接返回一个Future对象,同时hystrix创建一个新线程运行run(),调用程序通过Future.get()拿到run()的返回结果,而Future.get()是堵塞执行的
3、observe():事件注册前执行run()/construct()。以demo为例,第一步是事件注册前,先调用observe()自动触发执行run()/construct()(如果继承的是HystrixCommand,hystrix将创建新线程非堵塞执行run();如果继承的是HystrixObservableCommand,将以调用程序线程堵塞执行construct()),第二步是从observe()返回后调用程序调用subscribe()完成事件注册,如果run()/construct()执行成功则触发onNext()和onCompleted(),如果执行异常则触发onError()
4、toObservable():事件注册后执行run()/construct()。以demo为例,第一步是事件注册前,一调用toObservable()就直接返回一个Observable对象,第二步调用subscribe()完成事件注册后自动触发执行run()/construct()(如果继承的是HystrixCommand,hystrix将创建新线程非堵塞执行run(),调用程序不必等待run();如果继承的是HystrixObservableCommand,将以调用程序线程堵塞执行construct(),调用程序等待construct()执行完才能继续往下走),如果run()/construct()执行成功则触发onNext()和onCompleted(),如果执行异常则触发onError()
public class JedisCommandTest extends HystrixCommand<String> {
private final String name;
public JedisCommandTest(String name) {
//最少配置:指定命令组名(CommandGroup)
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")).andCommandPropertiesDefaults(
HystrixCommandProperties.Setter().withExecutionIsolationThreadTimeoutInMilliseconds(500)
));
this.name = name;
}
@Override
protected String run() throws Exception {
// 依赖逻辑封装在run()方法中
//TimeUnit.MILLISECONDS.sleep(1000);
//int i = 1/0;
return "Hello " + name +" thread:" + Thread.currentThread().getName();
}
@Override
protected String getFallback() {
return "exeucute Falled";
}
public static void main(String[] args) throws Exception{
//每个Command对象只能调用一次,不可以重复调用,
//重复调用对应异常信息:This instance can only be executed once. Please instantiate a new instance.
JedisCommandTest JedisCommand = new JedisCommandTest("Synchronous-hystrix");
//使用execute()同步调用代码,效果等同于:helloWorldCommand.queue().get();
String result = JedisCommand.execute();
System.out.println("result=" + result);
JedisCommand = new JedisCommandTest("Asynchronous-hystrix");
//异步调用,可自由控制获取结果时机,
Future<String> future = JedisCommand.queue();
//get操作不能超过command定义的超时时间,默认:1秒
result = future.get(100, TimeUnit.MILLISECONDS);
System.out.println("result=" + result);
System.out.println("mainThread=" + Thread.currentThread().getName());
System.out.println("=========================================================");
Observable<String> fs = new JedisCommandTest("World").observe();
fs.subscribe(new Action1<String>() {
public void call(String result) {
//执行结果处理,result 为HelloWorldCommand返回的结果
//用户对结果做二次处理.
System.out.println("result :"+result);
}
});
fs.subscribe(new Observer<String>() {
public void onCompleted() {
// onNext/onError完成之后最后回调
System.out.println("execute onCompleted");
}
public void onError(Throwable e) {
// 当产生异常时回调
System.out.println("onError " + e.getMessage());
e.printStackTrace();
}
public void onNext(String v) {
// 获取结果后回调
System.out.println("onNext: " + v);
}
});
}
}
二、降级
降级机制很简单,继承HystrixCommand只需重写getFallback(),继承HystrixObservableCommand只需重写resumeWithFallback()
三、熔断
熔断机制相当于电路的跳闸功能,举个栗子,我们可以配置熔断策略为当请求错误比例在10s内>50%时,该服务将进入熔断状态,后续请求都会进入fallback。
withCircuitBreakerRequestVolumeThreshold可以配置失败次数阀值,超过进入熔点。
withCircuitBreakerErrorThresholdPercentage可以配置失败的百分比阀值,超过进入熔断。
四、隔离
- 线程池隔离
不同服务通过使用不同线程池,彼此间将不受影响,达到隔离效果。通过andThreadPoolKey配置使用命名为ThreadPoolTest的线程池,实现与其他命名的线程池天然隔离,如果不配andThreadPoolKey则使用withGroupKey配置来命名线程池。
信号量隔离
线程隔离会带来线程开销,有些场景(比如无网络请求场景)可能会因为用开销换隔离得不偿失,为此hystrix提供了信号量隔离,当服务的并发数大于信号量阈值时将进入fallback。
通过withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)配置为信号量隔离。
通过withExecutionIsolationSemaphoreMaxConcurrentRequests配置执行并发数不能大于3,由于信号量隔离下无论调用哪种命令执行方法,hystrix都不会创建新线程执行run()/construct(),所以调用程序需要自己创建多个线程来模拟并发调用execute(),最后看到一旦并发线程>3,后续请求都进入fallback