Hystrix 为 微服务架构提供了一整套服务隔离、服务熔断和服务降级的解决方案。它是熔断器的一种实现,主要用于解决微服务架构的高可用及服务雪崩等问题
Hystrix 的特性如下:
Hystrix 的使用主要分为服务熔断、服务降级和服务监控三个方面
在 pom.xml 文件中引入 Hystrix 依赖,其中,spring-cloud-slarter-netflix-hystrix 和 hystrix-javanica 为 Hystrix 服务熔断所需的依赖,spring-cloud-netflix-hystrix-dashboard 为 Hystrix 服务监控所需的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
通过 @EnableHystrix 注解开启对服务熔断的支持,通过 @EnableHystrixDashboard 注解开启对服务监控的支持。注意,Hystrix 一般和服务发现配合使用,这里使 @EnableEurekaClient 开启了对服务发现客户端的支持
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@EnableHystrixDashboard
public class HystrixServiceApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixServiceApplication.class, args);
}
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
配置 application.properties 文件
#服务名
spring.application.name=hystrix
#服务的端口
server.port=9005
#注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka/
eureka.client.registry-fetch-interval-seconds=30
服务熔断和降级,定义了一个远程调用的方法 hystrixHandler(),并通过 @HystrixCommand(fallbackMethod="exceptionHandler") 在方法上定义了一个服务降级的命令,当远程方法调用失败时,Hystrix 会自动调用 fallbackMethod 来完成服务熔断和降级,这里会调用 exceptionHandler 方法
@Autowired
private RestTemplate restTemplate;
//定义服务降级命令
@HystrixCommand(fallbackMethod = "exceptionHandler")
@RequestMapping(value = "/service/hystrix", method = RequestMethod.GET)
public String hystrixHandler() {
return restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
}
public String exceptionHandler() {
return "提供者服务挂了";
}
上节中的远程调用请求必须等到网络请求返回结果后,才会执行后面的代码,即阻塞运行。而在实际使用过程中,应用程序常常希望使用非阻塞 IO 来更优雅地实现功能.Hyslrix 为非阻塞 IO 提供了两种实现方式,分别是表示将来式的 Future 和表示回调式的 Callable
定义 HystrixCommand
public class CommandFuture extends HystrixCommand<String> {
private String name;
private RestTemplate restTemplate;
public CommandFuture(String name, RestTemplate restTemplate) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
//1:通过 HystrixCommandKey 工厂定义依赖的名称
.andCommandKey(HystrixComnandKey.Factory.asKey("HelloWorld"))
//2:通过 HystrixThreadPoolKey 工厂定义线程池的名称
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
this.name = name;
this.restTemplate = restTemplate;
}
//3:定义远程调用的方法体
@Override
protected String run() {
String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
return result;
}
//4:服务降级的处理逻辑
@Override
protected String getFallback() {
return "远程服务异常";
}
}
以上代码通过继承 HystrixCommand 定义了一个 CommandFuture 来实现异步请求,其中,正常业务执行的逻辑在覆写的 run() 方法体中被执行,服务降级的方法在 getFallback() 中被执行。需要注意的是,这里使用 andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")) 实现了使用 HystrixCommandKey 工厂定义依赖的名称,每个 CommandKey 都代表一个依赖抽象,相同的依赖要使用相同的 CommandKey 名称。依赖隔离的本质敦是对相同
CommandKey 的依赖进行离,使用 andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")) 实现了基于 HystrixThreadPoolKey 工厂定义线程池的名称。当对同一业务的依赖进行资源隔离时,使用 CommandGroup 进行区分,但是当对同一依赖进行不同的远程调用时(例如,一个是 Redis 服务,一个是 HTTP 服务),则可以使用 HystrixThreadPoolKey 进行隔离区分
使用 HystrixCommand
@RequeatMapping(value = "/service/hystrix/future", method = RequestMethod.GET)
public String hystrixFutureHandler() throws ExecutionException, InterruptedException {
//定义基于Future的异步调用,请求会以队列的形式在线程池中被执行
Future<String> future = new CommandFuture("future", restTemplate).queue();
return future.get();
}
预定义一个回调任务,Callable 在发出请求后,主线程继续执行,在请求执行完成并返回结果后,Callable 会自动调用回调任务
定义 HystrixObservableCommand
public class CommandObservable extends HystrixObservabCommand<String> {
private String name;
private RestTemplate restTemplate;
public CommandObservable(String nane, RestTemplate restTemplate) {
super(HystrixConmandGroupKey.Factory.asKey("ExampleGroup"));
this.nane = name;
this.restTemplate = restTemplate;
}
//基于观察者模式的请求发布
@Override
protected Observable<String> construct () {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
//执行远程过程调用
if(!subscriber.isUnsubscribed()) {
String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
//将调用结果传递下去
subscriber.onNext(result):
subscriber.onCompleted();
}
} catch(Exception e) {
e.printStackTrace();
subscriber.onError(e);
}
}
}
}
//服务降级的处理逻辑
@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("远程服务异常”);
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
}
}
}
以上代码定义了名为 CommandObservable 的类,该类继承自 HystrixObservableCommand 接口,并通过覆写 HystrixObservableCommand 接口中的 construct() 实现观察者模式。具体实现为通过 Obsenvable.create() 创建并返回一个 Observable
使用 HystrixObservableCommand
public String hystrixCallableHandler() throws ExecutionException, InterruptedException {
List<String> list = new ArrayList<>();
//定义基于消息订间的异步调用,请求结果会以事件的方式通知
Observable<String> observable = new CommandObservable("observer", restTemplate).observe();
//基于观察者模式的清求结果订阅
observable.subscribe(new Observer<String>() {
//onCompleted方法在所有请求完成后执行@
@Override
public void onCompleted() {
System.out.println("所有请求已经完成...”);
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
//订阅调用事件,请求结果汇聚的地方,用集合将返回的结果收集起来
@Override
public void onNext(String s) {
System.out.printin("结果来了...");
list.add(s);
return list.toString();
}
}
}
以上代码通过 new CommandObservable("observer", restTemplate).observe() 定义了一个实现服务发布的命令。通过调用 abservabe.subscribe() 来实现基于观察者模式的请求结果订阅,其中,订阅的数据结果在 onNext() 中被通知,总体调用结果在 onCompleted() 中被通知。服务处理异常结果在 onError() 中被通知
HystrixDashboard 主要用于实时监控 Hystrix 的各项运行指标。通过 HystrixDashboard 可以查询 Hystrix 的实时信息,用于快速定位和发现问题。Hystrix Dashboard 的使用简单、方便,首先在 pom.xml 文件中加入 spring-cloud-netfix-hystrix-dashboard 依赖,然后使用 @EnableHystrixDashboard 注解开启 Dashboard 功能即可。在服务启动后,在浏览器地址栏中输人 http://127.0.0.1:9005/hystrix
,就可以看到监控界面