在分布式的环境中,不同的服务之间总是在相互依赖,难免有时候有的服务会开个小差,影响其他服务的正常运行。Hystrix
是Netflix
开发的一款可以帮助我们控制服务之间相互影响的库,保证我们在服务运行的过程中保证不会发生大面积的雪崩。
在项目中加入Hystrix
在Maven的pom.xml
中加入:
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>1.5.8</version>
</dependency>
虽然大名鼎鼎的Spring Cloud
社区将Netflix OSS
封装成了一组"全家桶"——Spring Cloud Netflix
,并且解决了很多问题,但我还是比较喜欢从原生的一套中学习。
使用Hystrix
HystrixCommand
是Hystrix
的核心类,Hystrix
采用了命令模式,我们可以将自己的逻辑封装到每一个对应的命令中,然后针对不同的逻辑做出相对应的反应。
这里创建一个例子:
public class CommandThatFailsFast extends HystrixCommand<String> {
private final boolean throwException;
public CommandThatFailsFast(boolean throwException) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.throwException = throwException;
}
/**
* 这个方法里面封装了正常的逻辑,我们可以传入正常的业务逻辑
*
* @return
* @throws Exception
*/
@Override
protected String run() throws Exception {
// 如果为true,这个方法丢出异常,如果为false就返回字符串
if (throwException) {
throw new RuntimeException("failure from CommandThatFailsFast");
} else {
return "success";
}
}
/**
* 这个方法中定义了出现异常时, 默认返回的值(相当于服务的降级)。
*
* @return
*/
@Override
protected String getFallback() {
return "default value";
}
}
在客户端我们实例化一个CommandThatFailsFast
对象之后,可以通过execute()
方法同步执行run()
方法里面的业务。
CommandThatFailsFast failsFast = new CommandThatFailsFast(false);
String str1 = failsFast.execute();
在HystrixCommand
的run()
方法中,如果抛出异常,getFallback()
方法就会在异常发生时,默认返回一些值,我们就可以在这个地方提供服务降级服务。这样可以为上层调用方(consumer)提供响应,避免服务的雪崩。
除此之外,我们可以利用RxJava
的Observable
对象(Hystrix
就是基于RxJava
开发的),来对HystrixCommand
的相应结果做出不同的反应:
Observable<String> fWorld = new CommandHelloWorld("World").observe();
fWorld.subscribe(new Observer<String>() {
// 当run()执行完
@Override
public void onCompleted() {
// nothing needed here
System.out.println("OnComplete: close function");
}
// 当发生异常的时候
@Override
public void onError(Throwable e) {
if (e instanceof HystrixRuntimeException) {
HystrixRuntimeException exception = (HystrixRuntimeException) e;
if (exception.getFailureType() == HystrixRuntimeException.FailureType.BAD_REQUEST_EXCEPTION) {
System.out.println("错误的请求");
} else if (exception.getFailureType() == HystrixRuntimeException.FailureType.TIMEOUT) {
System.out.println("超时异常");
}
}
e.printStackTrace();
}
// 每当事件进行一步的时候
@Override
public void onNext(String v) {
System.out.println("onNext: " + v);
}
});
命名空间
每一个实例化的HystrixCommand
对象都会拥有一个默认的名字——他们的类名,如果我们希望自定义这个名称,就需要在构造方法里面,预先设置好:
public CommandThatFailsFast(boolean throwException) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
this.throwException = throwException;
}
上面这个例子中,就将这个Command
的名字设置成了HelloWorld
。
除了设置名称之外,上面的代码里不难发现还设置了一个Command Group
。这个Command Group
会将同一组中的数据归档,用于数据的展现,告警等等。
ThreadPool是指为这个Command
提供服务的线程池,每一个HystrixCommand
都会关联到一个HystrixThreadPool
上,默认情况下Command Group
的线程池会成为HystrixCommand
的选择。 这个线程池为Hystrix
提供监控,Metrics推送,缓存等等使用。
通过Hystrix
,我们可以有效地防止在分布式环境中由于某一个服务的崩溃造成整个系统的影响。