在当今分布式系统的浪潮中,微服务架构因其灵活性和可扩展性而备受青睐,然而,随着服务数量的增长,如何保证系统的稳定性和可靠性成为一大挑战。面对服务间的依赖可能导致的级联故障,Hystrix 作为一款强大的容错中间件,提供了服务熔断、降级以及依赖隔离等功能,有效防止了系统因单点故障而引发的雪崩效应。本文将深入探讨 Hystrix 的核心机制,包括其服务熔断与降级流程、依赖隔离策略,以及如何利用其监控功能来提升系统的可观测性。
Hystrix是springCloud的组件之一,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
1. Future
定义 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();
}
2. Callable
预定义一个回调任务,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 对象,在创建对象时,通过 new Observable.OnSubscribe() 实现消息的监听和处理。其中,call 方法用于消息的接收和业务的处理,在消息处理完成后通过 subscriber.onNext(result) 将调用结果传递下去,当所有任务都执行完成时通过 subscriber.onCompleted() 将总体执行结果发布出去。resumeWithFallback 方法是服务降级的处理逻辑,当服务出现异常时,通过 subscriber.onNext("远程服务异常") 进行服务熔断和异常消息的发布,实现服务降级处理
使用 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
,就可以看到监控界面
本文被 Java编程 专题收录