H概念

在分布式架构中, 当某个服务单元发生故障之后, 通过短路器的故障监控, 向调用方返回一个错误响应, 而不是长时间的等待, 这样就不会使得线程因调用故障服务被长时间占用而不释放, 避免了故障在分布式系统中的蔓延.

Spring Cloud Hystrix实现了短路器, 线程隔离等一系列保护功能, 该框架的目标在于控制那些访问远程系统, 服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力, Hystrix具备服务降级, 服务熔断, 线程和信号隔离, 请求缓存, 请求合并以及服务监控等强大功能.

快速入门

demo结构:
eurekaServer为注册中心,
hello-service有俩实例,
ribbon-consumer为负载均衡调用方,
现由ribbon-consumer调用hello-service服务, 发10次请求, 由负载均衡策略每个实例访问5次
image.png
image.png
若某一个实例突然挂掉, 没上hystrix第一次访问会报500错误, 然后下一次请求, 注册中心会把挂掉的服务剔除, 就不再报错了
ribbon-consumer工程使用hystrix优化:
1.加依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>

2.启动类加注解@EnableCircuitBreaker, 或者直接使用@SpringCloudApplication注解

  1. /**
  2. * @author xinzhang
  3. * @date 2020/8/25 15:10
  4. */
  5. @EnableEurekaClient
  6. @EnableCircuitBreaker
  7. @SpringBootApplication
  8. public class RibbonDemoApplication {
  9. public static void main(String[] args) {
  10. SpringApplication.run(RibbonDemoApplication.class, args);
  11. }
  12. }
  1. /**
  2. * @author Spencer Gibb
  3. */
  4. @Target(ElementType.TYPE)
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. @Inherited
  8. @SpringBootApplication
  9. @EnableDiscoveryClient
  10. @EnableCircuitBreaker
  11. public @interface SpringCloudApplication {
  12. }

3.调用方法指定fallback回调方法, 若访问失败, 则会调用回调方法
在helloFallback方法中添加参数Throwable, 此Throwable即为具体的异常信息

  1. /**
  2. * @author xinzhang
  3. * @date 2020/8/25 15:16
  4. */
  5. @RestController
  6. @RequestMapping("/ribbon")
  7. public class RibbonController {
  8. @Autowired
  9. private RestTemplate restTemplate;
  10. @GetMapping
  11. @HystrixCommand(ignoreExceptions = {IOException.class},fallbackMethod = "helloFallback",groupKey = "TestGroupName",commandKey
  12. = "TestCommandKey",threadPoolKey = "TestThreadPoolKey")
  13. public String test() {
  14. for (int i = 0; i < 10; i++) {
  15. ResponseEntity<String> entity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
  16. System.out.println("返回的结果是: ------------>" + entity.getBody());
  17. }
  18. return "服务正常";
  19. }
  20. public String helloFallback(Throwable e) {
  21. return "服务挂掉了!";
  22. }
  23. }

断掉某一个实例后, 第一次访问, 不再报错, 测试如下
image.png

HystrixCommand的命令模式

命令及其实现

  1. public interface Command {
  2. /**
  3. * 执行方法
  4. */
  5. void execute();
  6. }
  7. public class ConcretCommand implements Command {
  8. private Receiver receiver;
  9. public ConcretCommand(Receiver receiver) {
  10. this.receiver = receiver;
  11. }
  12. @Override
  13. public void execute() {
  14. receiver.action();
  15. }
  16. }

命令接收者

  1. public class Receiver {
  2. public void action() {
  3. System.out.println("具体的执行逻辑!");
  4. }
  5. }

调用方调用命令的执行方法, 执行方法的实现是调用接收者的执行方法

  1. public class Invoker {
  2. private Command command;
  3. public void setCommand(Command command) {
  4. this.command = command;
  5. }
  6. public void action() {
  7. command.execute();
  8. }
  9. }

测试

  1. public class Test {
  2. public static void main(String[] args) {
  3. Command concretCommand = new ConcretCommand(new Receiver());
  4. Invoker invoker = new Invoker();
  5. invoker.setCommand(concretCommand);
  6. invoker.action();
  7. }
  8. }

如上, 调用者Invoker与操作者Receiver通过command命令实现了解耦, 对于调用者来说可以为其注入多个命令, 而不用关心命令的具体实现。Invoker与Receiver的关系类似于“请求-响应”模式, 所以它比较适用于实现记录日志, 撤销操作, 队列请求等。
image.png

断路器原理

略, 改日分析源码再战

依赖隔离

hystrix同docker一样使用“舱壁模式”为每一个依赖服务创建一个独立的线程池, 这样就算某个依赖服务出现延迟过高的情况, 也只是对该依赖服务的调用产生影响,而不会拖慢其他的依赖服务。
image.png

使用详解

创建请求命令

HystrixCommand, 用来封装具体的依赖服务调用逻辑

  1. 使用注解,见上面demo示例
  2. 继承HystrixCommand类

    1. /**
    2. * @author xinzhang
    3. * @date 2020/9/18 15:10
    4. */
    5. public class TestCommand extends HystrixCommand<String> {
    6. private RestTemplate restTemplate;
    7. /**
    8. * 参数
    9. */
    10. private String org;
    11. public TestCommand(RestTemplate restTemplate, String org) {
    12. super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("TestGroupName"))
    13. .andCommandKey(HystrixCommandKey.Factory.asKey("TestCommandKey"))
    14. .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("TestThreadPoolKey")));
    15. this.restTemplate = restTemplate;
    16. this.org = org;
    17. }
    18. @Override
    19. protected String run() throws Exception {
    20. ResponseEntity<String> entity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
    21. return entity.getBody();
    22. }
    23. @Override
    24. protected String getFallback() {
    25. return "服务调用失败!";
    26. }
    27. @Override
    28. protected Exception getExceptionFromThrowable(Throwable t) {
    29. return super.getExceptionFromThrowable(t);
    30. }
    31. }
    1. @GetMapping("/1")
    2. public String test1() throws ExecutionException, InterruptedException {
    3. // 异步调用
    4. Future<String> future = new TestCommand(restTemplate, "测试参数").queue();
    5. String s = future.get();
    6. System.out.println(s);
    7. // 同步调用
    8. return new TestCommand(restTemplate, "测试参数").execute();
    9. }
  3. 继承HystrixObservableCommand,实现响应式执行

服务降级

fallback是hystrix命令执行失败时使用的后备方法,用来实现服务的降级处理逻辑.
image.png

异常处理

  1. 通过 @HystrixCommand的 ignoreExceptions可以排除异常, 接收到排除的异常时不会走fallback方法
  2. 不管是注解式还是继承都可以拿到异常的具体信息,来做特定的处理,见上面demo

命令名称,分组以及线程池划分

Hystrix默认根据组来划分线程池,也可以给command指定线程池名称, 见上面demo

请求缓存

没啥用,不如redis

请求合并

在很短的时间内(默认10ms),对同一依赖服务的多个请求进行整合转成批量请求,服务提供方也需提供批量的接口
image.png

如上, 几乎没机会用, 略

属性详解

image.png

详情略, 看书吧