Hystrix概述.

Hytrix工作原理https://github.com/Netflix/Hystrix/wiki/How-it-Works#benefits-of-thread-pools

spring cloud 用的是 hystrix,是一个容错组件。Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。

Hystrix主要有以下几点功能:

  1. 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
  2. 防止雪崩。
  3. 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
  4. 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
  5. 资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
  6. 快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
  7. 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
  8. 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
  9. 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。前面有介绍。 ```powershell 1、设置失败次数阈值、http请求线程池

2、发出一个远程调用请求,消耗一个线程

3、判断连接超时,如果超时,记录超时次数,并将服务记录下来

4、根据重试配置重试,依旧失败

5、返回服务降级处理

6、当失败次数到达阈值时进行服务熔断,后续请求不发起远程调用,直接返回降级处理结果

7、一定时间后再次尝试远程调用,成功返回则取消熔断

  1. <a name="vEHyX"></a>
  2. ### 单独使用Hytrix
  3. ```powershell
  4. package com.ixiaoyu2.web.hystrix;
  5. import com.netflix.hystrix.HystrixCommand;
  6. import com.netflix.hystrix.HystrixCommandGroupKey;
  7. import com.netflix.hystrix.HystrixThreadPoolKey;
  8. import java.util.concurrent.ExecutionException;
  9. import java.util.concurrent.Future;
  10. /**
  11. * @author :Administrator
  12. * @date :2022/4/19 0019
  13. */
  14. public class HystrixDemo extends HystrixCommand {
  15. protected HystrixDemo(HystrixCommandGroupKey group) {
  16. super(group);
  17. }
  18. protected HystrixDemo(HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {
  19. super(group, threadPool);
  20. }
  21. @Override
  22. protected Object run() throws Exception {
  23. System.out.println("执行逻辑");
  24. int i = 1 / 0;
  25. return "执行结束,i=" + i;
  26. }
  27. @Override
  28. protected Object getFallback() {
  29. return "fallback,i=-1";
  30. }
  31. public static void main(String[] args) {
  32. Future<String> futureResult = new HystrixDemo(HystrixCommandGroupKey.Factory.asKey("ext")).queue();
  33. String res = "";
  34. String s = null;
  35. try {
  36. s = futureResult.get();
  37. } catch (InterruptedException | ExecutionException e) {
  38. e.printStackTrace();
  39. }
  40. System.out.println("结果:" + s);
  41. }
  42. }

执行出现异常,执行getFallback()方法
image.png

RestTemplate整合Hystrix

手动模拟服务降级

@GetMapping("/users")
public List<User> query() {
    List<User> list = new ArrayList<>(10);
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for (int i = 0; i < 10; i++) {
        list.add(new User(i + 1, "黑岩射手:number" + i + 1, 18 + i));
    }
    return list;
}
@HystrixCommand(fallbackMethod = "fallback")
public List<User> users() {
    String path = servicePath("users");
    return restTemplate.getForObject(path, List.class);
}


public List<User> fallback() {
    List<User> users = new ArrayList<>();
    users.add(new User(0, "我是替补", 19));
    return users;
}
@GetMapping("/users")
public List<User> users() {
    return consumerService.users();
}
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://ixiaoyu2:ixiaoyu2@127.0.0.1:7000/eureka
    healthcheck:
      enabled: true
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 3000

测试结果
image.png

Feign整合Hystrix

public interface UserApi {
    /**
     * 获取全部用户
     *
     * @return 返回用户列表
     */

    List<User> users();

    /**
     * 根据id获取用户
     *
     * @param id id
     * @return 用户
     */

    User oneUser(@RequestParam("id") Integer id);

    /**
     * 添加用户
     *
     * @param map 封装用户信息
     * @return 新创建的用户
     */

    User add(@RequestParam HashMap<String, String> map);
}
@RestController
public class ProviderController implements UserApi {
    @Override
    public List<User> users() {
        List<User> list = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            list.add(new User(i + 1, "黑岩射手:number" + i + 1, 18 + i));
        }
        return list;
    }

    @Override
    public User oneUser(Integer id) {
        try {
            // 模拟业务超时
            System.out.println("要睡4s啦~");
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("接收的id: " + id);
        return new User(id, "Black Rock Shooter", id + 1);
    }

    @Override
    public User add(HashMap<String, String> map) {
        System.out.println(map);
        return new User(1, map.get("name"), Integer.parseInt(map.get("age")));
    }
}

@FeignClient(name = "provider", fallback = AliveBack.class)
@Qualifier
public interface UserService extends UserApi {
    @GetMapping("provider/users")
    @Override
    List<User> users();

    @GetMapping("provider/user")
    @Override
    User oneUser(Integer id);

    @PostMapping("provider/user")
    @Override
    User add(HashMap<String, String> map);
}
@Component
public class AliveBack implements UserService {
    @Override
    public List<User> users() {
        List<User> list = new ArrayList<>();
        list.add(new User(0, "我是替补", 19));
        return list;
    }

    @Override
    public User oneUser(Integer id) {
        return new User(1, "w我是替补", 19);
    }

    @Override
    public User add(HashMap<String, String> map) {
        return new User(1, "w我是替补", 19);
    }
}
@RestController
@RequestMapping("consumer")
public class ConsumerController {

    @Autowired
    @Qualifier
    UserService userService;

    @GetMapping("/users")
    public List<User> users() {
        return userService.users();
    }

    @GetMapping("/user")
    public User oneUser(Integer id) {
        return userService.oneUser(id);
    }

    @PostMapping("/user")
    public User oneUser2(@RequestParam HashMap<String, String> map) {
        System.out.println(map);
        return userService.add(map);
    }
}
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://ixiaoyu2:ixiaoyu2@127.0.0.1:7000/eureka
    healthcheck:
      enabled: true
server:
  port: 8081
logging:
  level:
    com.ixiaoyu2: debug

ribbon:
  # 连接超时时间(ms)
  ConnectTimeout: 1000
  # 业务逻辑超时时间(ms)
  ReadTimeout: 4000
  # 同一台实例最大重试次数,不包括首次调用
  MaxAutoRetries: 1
  # 重试负载均衡其他的实例最大重试次数,不包括首次调用
  MaxAutoRetriesNextServer: 1
  # 是否所有操作都重试
  OkToRetryOnAllOperations: false
#开启Hystrix
feign:
  hystrix:
    enabled: true

注意:
(1)AliveBack实现了UserService,也是一个Feign实例,因此在ConsumerController注入时需要使用@Qualifier注解
(2)AliveBack实现了UserService,因此UserApi不能加@RequestMapping()注解

使用FallbackFactory

@Component
public class AFallBackFactory implements FallbackFactory<UserService> {
    User user = new User(1, "替补xx", 0);

    @Override
    public UserService create(Throwable throwable) {
        return new UserService() {
            @Override
            public List<User> users() {
                System.out.println("异常信息如下:");
                System.out.println(throwable.getLocalizedMessage());
                System.out.println("异常堆栈信息如下:");
                throwable.printStackTrace();
                return Collections.singletonList(user);
            }

            @Override
            public User oneUser(Integer id) {
                System.out.println("异常信息如下:");
                System.out.println(throwable.getLocalizedMessage());
                System.out.println("异常堆栈信息如下:");
                throwable.printStackTrace();
                return user;
            }

            @Override
            public User add(HashMap<String, String> map) {
                System.out.println("异常信息如下:");
                System.out.println(throwable.getLocalizedMessage());
                System.out.println("异常堆栈信息如下:");
                throwable.printStackTrace();
                return user;
            }
        };
    }
}
@FeignClient(name = "provider", fallbackFactory = AFallBackFactory.class)
@Qualifier
public interface UserService extends UserApi {

    @Override
    @GetMapping("provider/users")
    List<User> users();

    @Override
    @GetMapping("provider/user")
    User oneUser(@RequestParam Integer id);

    @Override
    @PostMapping("provider/user")
    User add(@RequestBody HashMap<String, String> map);
}

信号量隔离与线程隔离

默认情况下hystrix使用线程池控制请求隔离
线程池隔离技术,是用 Hystrix 自己的线程去执行调用;
而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。
信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。

线程隔离

Hytrix 线程池大小为10,队列大小为5
image.png