H概念
在分布式架构中, 当某个服务单元发生故障之后, 通过短路器的故障监控, 向调用方返回一个错误响应, 而不是长时间的等待, 这样就不会使得线程因调用故障服务被长时间占用而不释放, 避免了故障在分布式系统中的蔓延.
Spring Cloud Hystrix实现了短路器, 线程隔离等一系列保护功能, 该框架的目标在于控制那些访问远程系统, 服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力, Hystrix具备服务降级, 服务熔断, 线程和信号隔离, 请求缓存, 请求合并以及服务监控等强大功能.
快速入门
demo结构:
eurekaServer为注册中心,
hello-service有俩实例,
ribbon-consumer为负载均衡调用方,
现由ribbon-consumer调用hello-service服务, 发10次请求, 由负载均衡策略每个实例访问5次
若某一个实例突然挂掉, 没上hystrix第一次访问会报500错误, 然后下一次请求, 注册中心会把挂掉的服务剔除, 就不再报错了
ribbon-consumer工程使用hystrix优化:
1.加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.启动类加注解@EnableCircuitBreaker, 或者直接使用@SpringCloudApplication注解
/**
* @author xinzhang
* @date 2020/8/25 15:10
*/
@EnableEurekaClient
@EnableCircuitBreaker
@SpringBootApplication
public class RibbonDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonDemoApplication.class, args);
}
}
/**
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
3.调用方法指定fallback回调方法, 若访问失败, 则会调用回调方法
在helloFallback方法中添加参数Throwable, 此Throwable即为具体的异常信息
/**
* @author xinzhang
* @date 2020/8/25 15:16
*/
@RestController
@RequestMapping("/ribbon")
public class RibbonController {
@Autowired
private RestTemplate restTemplate;
@GetMapping
@HystrixCommand(ignoreExceptions = {IOException.class},fallbackMethod = "helloFallback",groupKey = "TestGroupName",commandKey
= "TestCommandKey",threadPoolKey = "TestThreadPoolKey")
public String test() {
for (int i = 0; i < 10; i++) {
ResponseEntity<String> entity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
System.out.println("返回的结果是: ------------>" + entity.getBody());
}
return "服务正常";
}
public String helloFallback(Throwable e) {
return "服务挂掉了!";
}
}
断掉某一个实例后, 第一次访问, 不再报错, 测试如下
HystrixCommand的命令模式
命令及其实现
public interface Command {
/**
* 执行方法
*/
void execute();
}
public class ConcretCommand implements Command {
private Receiver receiver;
public ConcretCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
命令接收者
public class Receiver {
public void action() {
System.out.println("具体的执行逻辑!");
}
}
调用方调用命令的执行方法, 执行方法的实现是调用接收者的执行方法
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action() {
command.execute();
}
}
测试
public class Test {
public static void main(String[] args) {
Command concretCommand = new ConcretCommand(new Receiver());
Invoker invoker = new Invoker();
invoker.setCommand(concretCommand);
invoker.action();
}
}
如上, 调用者Invoker与操作者Receiver通过command命令实现了解耦, 对于调用者来说可以为其注入多个命令, 而不用关心命令的具体实现。Invoker与Receiver的关系类似于“请求-响应”模式, 所以它比较适用于实现记录日志, 撤销操作, 队列请求等。
断路器原理
略, 改日分析源码再战
依赖隔离
hystrix同docker一样使用“舱壁模式”为每一个依赖服务创建一个独立的线程池, 这样就算某个依赖服务出现延迟过高的情况, 也只是对该依赖服务的调用产生影响,而不会拖慢其他的依赖服务。
使用详解
创建请求命令
HystrixCommand, 用来封装具体的依赖服务调用逻辑
- 使用注解,见上面demo示例
继承HystrixCommand类
/**
* @author xinzhang
* @date 2020/9/18 15:10
*/
public class TestCommand extends HystrixCommand<String> {
private RestTemplate restTemplate;
/**
* 参数
*/
private String org;
public TestCommand(RestTemplate restTemplate, String org) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("TestGroupName"))
.andCommandKey(HystrixCommandKey.Factory.asKey("TestCommandKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("TestThreadPoolKey")));
this.restTemplate = restTemplate;
this.org = org;
}
@Override
protected String run() throws Exception {
ResponseEntity<String> entity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
return entity.getBody();
}
@Override
protected String getFallback() {
return "服务调用失败!";
}
@Override
protected Exception getExceptionFromThrowable(Throwable t) {
return super.getExceptionFromThrowable(t);
}
}
@GetMapping("/1")
public String test1() throws ExecutionException, InterruptedException {
// 异步调用
Future<String> future = new TestCommand(restTemplate, "测试参数").queue();
String s = future.get();
System.out.println(s);
// 同步调用
return new TestCommand(restTemplate, "测试参数").execute();
}
继承HystrixObservableCommand,实现响应式执行
略
服务降级
fallback是hystrix命令执行失败时使用的后备方法,用来实现服务的降级处理逻辑.
异常处理
- 通过 @HystrixCommand的 ignoreExceptions可以排除异常, 接收到排除的异常时不会走fallback方法
- 不管是注解式还是继承都可以拿到异常的具体信息,来做特定的处理,见上面demo
命令名称,分组以及线程池划分
Hystrix默认根据组来划分线程池,也可以给command指定线程池名称, 见上面demo
请求缓存
没啥用,不如redis
请求合并
在很短的时间内(默认10ms),对同一依赖服务的多个请求进行整合转成批量请求,服务提供方也需提供批量的接口
如上, 几乎没机会用, 略
属性详解
详情略, 看书吧