熔断和服务降级对一个程序员来说一定不陌生,比如在面试时就可能被问到,你有没有使用过Hystrix,他是怎么实现熔断的,如果你回答说我在配置文件中配置了开启熔断,然后通过熔断@HystrixCommand在接口方法上进行标记,那恭喜你,肯定就是gg了。
现在就来说说Hystrix他能干啥,他的原理是什么。
优点
1 服务降级 熔断
2 线程信号隔离
3 请求缓存 请求合并以及服务监控
老样子,还是启动个项目,先入个门,启动hello-server服务分别通过8081端口和8082端口启动,再启动一个ribbon-consumer服务
/**
* 启动ribbon-consumer服务并通过EnableCircuitBreaker开启熔断
* EnableDiscoveryClient 注册到注册中心
/**
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
这里面说一下,其实可以用另外一个注解替代就是@SpringCloudApplication 他里面的内容是
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
我们看到是包含上面注解的,然后访问eruka
这里面说说怎么让一个服务通过不同的端口启动两次在idea上
我们先在idea中增加一个服务,选中要加载的主类,并配置端口号,然后启动就可以了
然后我们访问http://localhost:9000/ribbon-consumer
得到了接口的返回结果,看一下接口代码
@HystrixCommand(fallbackMethod = "helloFallback", commandKey = "helloKey")
public String hello() {
long start = System.currentTimeMillis();
StringBuilder result = new StringBuilder();
// GET
result.append(restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody()).append("<br>");
}
}
public String helloFallback() {
return "error";
}
我们看到此方法访问了hello-service服务,这时候我们把hello-service服务关闭,再访问一次
这时候我们看到,得到的结果就是指定的降级方法helloFallback() 返回的“error”。
下面解析下他的原理,先看下他的工作流程
我们看到工作流程中的最开始是起源于两个类HystrixCommand与HystrixObservableCommand类,想一想,Hystrix实现的熔断呀,监控的功能能和这两个类有什么关系呢?
我们发现这两个类都有一个相同点,就是都带Command,而这个Command就是Hystrix的核心,也就是他其实是使用了命令模式来实现的。
命令模式是设计模式中的一种,我们经常说我们使用不到设计模式,其实看源码,本身就是对设计模式的学习,那我们来看看命令模式是用来干啥的,先看个图
然后看下代码
public class CommandPattern {
public static void main(String[] args) {
Receiver receiver = new Receiver()
Command cmd = new ConcreteCommand(receiver);
Invoker ir = new Invoker(cmd);
System.out.println("客户访问调用者的call()方法...");
ir.call();
}
}
//调用者
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void call() {
System.out.println("调用者执行命令command...");
command.execute();
}
}
//抽象命令
interface Command {
void execute();
}
//具体命令
class ConcreteCommand implements Command {
private Receiver receiver;
ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
//接收者
class Receiver {
public void action() {
System.out.println("接收者的action()方法被调用...");
}
}
其实命令模式挺简单的,就是将调用者和接收者中间加一个中间层,隔离开,从而达到解耦的目的,并且在解耦的同时,我们也可以在命令中增加一些我们想要做的事,而且命令模式的中间层是抽象的,所以我们可以选择不同的命令实现来做不同的事。
简单来说命令模式就是由4部分构成,调用者,接收者,抽象的命令,以及对命令的实现(可能存在多个,自己选择)
不同的命令实现在hystrix中主要做了回调callBack,请求排队,命令的撤销等,所以说hystrix的核心就是这个命令模式。
通过工作流程图我们看到hystrix有两个命令类,他们分别对应2中执行方式,一共4中执行方式
excute,queue,oberve,toObservable.
这四种最终都用到了RxJava的响应式编程方式。
下面我们梳理下流程
1 创建HystrixCommand与HystrixObservableCommand对象
2 命令执行 通过excute,queue,oberve,toObservable
3 判断有没有开启请求缓存
4 看断路器有没有打开,如果打开就fallback
5 看线程池 信号量是否被占满,如果占满 fallback
6 计算断路器的健康度
7 fallback处理
8 返回成功的相应
以上就是Hystrix的工作流程,以及Hystrix的基本思想,Hystrix的内容还有很多,如果对Hystrix感兴趣这篇文章算是一个入门,希望对大家能够有所帮助