Hystrix的功能
1.请求熔断:当HystrixCommand请求后端服务失败数量超过一定比例(默认50%),断路器会切换到开路状态(Open).这时所有请求会直接失败而不会发送到后端服务.断路器保持在开路状态一段时间后(默认5秒),自动切换到半开路状态(HALF-OPEN).这时会判断下一次请求的返回情况,如果请求成功,断路器切回闭路状态(CLOSED),否则重新切换到开路状态(OPEN).如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用
2.服务降级:Fallback相当于是降级操作. 对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值.fallback方法的返回值一般是设置的默认值或者来自缓存.告知后面的请求服务不可用了
3.线程隔离:Hystrix在用户请求和服务之间加入了线程池。Hystrix为每个依赖调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。线程数是可以被设定的。 原理:用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,则会进行降级处理,用户的请求不会被阻塞,至少可以看到一个执行结果(例如返回友好的提示信息),而不是无休止的等待或者看到系统崩溃。
4、请求缓存:这个缓存是基于request的,因为每次请求来之前都必须HystrixRequestContext.initializeContext();进行初始化,每请求一次controller就会走一次filter,上下文又会初始化一次,前面缓存的就失效了,又得重新来。
5、请求合并:把重复的请求批量的用一个HystrixCommand命令去执行,以减少通信消耗和线程数的占用,默认合并10ms内的请求
优点:减少了通信开销,
缺点:请求延迟增加
创建Hystrix模块
添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.top</groupId>
<artifactId>spring-cloud</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>hystrix-client-8007</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hystrix-client-8007</name>
<description>Hystrix客户端8007</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
</dependency>
添加配置,同样到注册中心注册服务
server:
port: 8007
spring:
application:
name: hystrix-client-8007
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/
在启动类上添加@EnableCircuitBreaker表示允许熔断器
启动类上配置一个RestTemplate ,等会用这个去调用服务
@EnableEurekaClient
@EnableCircuitBreaker
@SpringBootApplication
public class HystrixClient8007Application {
public static void main(String[] args) {
SpringApplication.run(HystrixClient8007Application.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
HystrixCommand继承方式
public class MyHystrixCommand extends HystrixCommand<String> {
private RestTemplate restTemplate;
public MyHystrixCommand(RestTemplate restTemplate){
super(HystrixCommandGroupKey.Factory.asKey("MyHystrixCommand"));
this.restTemplate = restTemplate;
}
//HystrixCommand会执行这个方法发送请求
@Override
protected String run() throws Exception {
return restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody();
}
//HystrixCommand会在熔断器开路、线程池拒绝、run方法执行过程中出现错误、超时等情况时执行该降级方法
@Override
protected String getFallback() {
return "调用eureka-client服务失败";
}
}
controller方法
@RestController
public class MyHystrixController {
@Autowired
private RestTemplate restTemplate;
//同步执行
@RequestMapping("/execute")
public void execute(){
MyHystrixCommand myHystrixCommand = new MyHystrixCommand(restTemplate);
System.out.println(myHystrixCommand.execute());
}
//异步执行
@RequestMapping("/queue")
public void queue() throws ExecutionException, InterruptedException {
MyHystrixCommand myHystrixCommand = new MyHystrixCommand(restTemplate);
System.out.println(myHystrixCommand.queue().get());
}
}
首先启动两个注册中心,两个客户端,接着启动Hystrix-client-8007模块,进行访问
当我们关掉8004客户端时,会看到下面的情况,首先服务依然会轮询访问,当请求发送到8004客户端时,这时服务会调用失败,就会走hystrix的降级方法(getFallback)。最后会熔断掉8004的通道,将请求全部发送到8003客户端。当8004重启上线之后,服务又会接着轮询发送请求。
HystrixCommand注解方式
@Service
public class MyHystrixService {
@Autowired
private RestTemplate restTemplate;
//同步请求
@HystrixCommand(fallbackMethod = "getFallBack")
public String execute(){
return restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody();
}
//异步请求
@HystrixCommand(fallbackMethod = "getFallBack")
public Future<String> queue(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody();
}
@Override
public String get() throws UnsupportedOperationException {
return invoke();
}
};
}
public String getFallBack(){
return "调用eureka-client服务失败";
}
}
这里要注意,异步请求的时候同时要实现get方法,否则会报这个错,点进get源码看一下就知道了
java.lang.UnsupportedOperationException: AsyncResult is just a stub and cannot be used as complete implementation of Future
controller中添加方法
@Autowired
private MyHystrixService myHystrixService;
//同步执行
@RequestMapping("/execute2")
public void execute2(){
System.out.println(myHystrixService.execute());
}
//异步执行
@RequestMapping("/queue2")
public void queue2() throws ExecutionException, InterruptedException {
System.out.println(myHystrixService.queue().get());
}
测试结果和上面一样,这里就不演示了。
HystrixObservableCommand继承方式
HystrixObservableCommand,其实这种模式就运用了Java的RX编程中,RxJava 是基于Java观察者设计模式的。
RxJava 最核心的两个东西是Observable(被观察者,事件源)和Subscriber(观察者)。Observable 发出一系列事件,Subscriber 处理这些事件。一个 Observable 可以发出零个或者多个事件,直到结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onCompleted()或者Subscriber.onError()结束
public class MyHystrixObservableCommand extends HystrixObservableCommand<String> {
private RestTemplate restTemplate;
public MyHystrixObservableCommand(RestTemplate restTemplate){
super(HystrixCommandGroupKey.Factory.asKey("MyHystrixObservableCommand"));
this.restTemplate = restTemplate;
}
//执行逻辑
@Override
protected Observable<String> construct() {
return Observable.create(subscriber -> {
try {
if (!subscriber.isUnsubscribed()){
//将结果收集起来
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
//通知执行完成
subscriber.onCompleted();
}
} catch (Exception e) {
subscriber.onError(e);
}
});
}
//服务降级
@Override
public Observable<String> resumeWithFallback(){
return Observable.create(subscriber -> {
try {
if (!subscriber.isUnsubscribed()){
subscriber.onNext("调用eureka-client服务失败");
subscriber.onCompleted();
}
} catch (Exception e) {
subscriber.onError(e);
}
});
}
}
controller方法:
@RestController
public class MyHystrixObservableController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/observe")
public void observe(){
List<String> list = new ArrayList<>();
MyHystrixObservableCommand myHystrixObservableCommand = new MyHystrixObservableCommand(restTemplate);
//冷执行
//Observable<String> observe = myHystrixObservableCommand.toObservable();
//热执行
Observable<String> observe = myHystrixObservableCommand.observe();
observe.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("执行完成");
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void onNext(String result) {
System.out.println("收集结果");
list.add(result);
}
});
System.out.println(list);
}
}
执行的结果:
关闭8004客户端的访问结果,请求发送到8003客户端时正常,当发送到8004时会调用降级方法。最后hystrix会熔断掉8004的通道,将请求全部发送到8003,直到8004修复上线
HystrixObservableCommand注解方式
@Service
public class MyHystrixObservableService {
@Autowired
private RestTemplate restTemplate;
/**
* ObservableExecutionMode.EAGER 热执行(默认)
* ObservableExecutionMode.LAZY 冷执行
* @return
*/
@HystrixCommand(fallbackMethod = "fallback", observableExecutionMode = ObservableExecutionMode.LAZY)
public Observable<String> construct(){
return Observable.create(subscriber ->{
try {
if (!subscriber.isUnsubscribed()){
//将结果收集起来
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
subscriber.onNext(restTemplate.getForEntity("http://eureka-client/sayHello/",String.class).getBody());
//通知执行完成
subscriber.onCompleted();
}
}catch (Exception e){
subscriber.onError(e);
}
});
}
public Observable<String> fallback(){
return Observable.create(subscriber -> {
try {
if (!subscriber.isUnsubscribed()){
subscriber.onNext("调用eureka-client服务失败");
subscriber.onCompleted();
}
} catch (Exception e) {
subscriber.onError(e);
}
});
}
}
controller层面的代码调用和上面类似:
@Autowired
private MyHystrixObservableService myHystrixObservableService;
@RequestMapping("/observe2")
public void observe2(){
List<String> list = new ArrayList<>();
Observable<String> observe = myHystrixObservableService.construct();
observe.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("执行完成");
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void onNext(String result) {
System.out.println("收集结果");
list.add(result);
}
});
System.out.println(list);
}
执行结果和上面一样。
另外服务降级方法还可以进行二次降级,但是一般没人这么干
如果想在降级方法中获取异常,只需要加上 Throwable就可以
@HystrixCommand(fallbackMethod = "fallback2")
public String fallback(Throwable throwable){
System.out.println(throwable.getMessage());
return "error";
}
总结:
HystrixCommand依赖调用方法是run,服务降级方法是getFallback
HystrixObservableCommand依赖调用方法是construct,服务降级方法是resumeWithFallback
HystrixCommand是发出一个请求,返回一个结果
- execute() — 从依赖的服务返回一个单一的结果对象,同步阻塞式;
- queue() — 返回一个Future对象,异步非阻塞式;
HystrixObservableCommand可以发出多个请求,返回一个结果
- observe() — 返回Obervable对象,热执行
- toObservable() — 返回Obervable对象,冷执行
热执行就是不管你事件有没有注册完(onCompleted(),onError,onNext这三个事件注册),就去执行我的业务方法即(HystrixObservableCommand实现类中的construct()方法)
冷执行就是,事件监听方法注册完成后,才执行业务方法
相关阅读
项目代码
SpringCloud 汇总【Greenwich 版】
SpringCloud(一):Eureka注册中心【Greenwich 版】
SpringCloud(二):Ribbon负载均衡【Greenwich 版】
SpringCloud(三):Feign声明式服务调用【Greenwich 版】
SpringCloud(四):Hystrix熔断器介绍【Greenwich 版】
SpringCloud(五):Hystrix的请求熔断与服务降级【Greenwich 版】
SpringCloud(六):Hystrix的请求合并【Greenwich 版】
SpringCloud(七):Hystrix仪表盘与Turbine集群监控【Greenwich 版】
SpringCloud(八):Zuul网关【Greenwich 版】
SpringCloud(九):Config配置中心【Greenwich 版】
SpringCloud(十):Bus消息总线【Greenwich 版】
SpringCloud(十一):Stream消息驱动 + RabbitMQ【Greenwich 版】
SpringCloud(十二):Sleuth链路跟踪【Greenwich 版】