文档章节

Hystrix 使用指南:基本使用

编走编想
 编走编想
发布于 2017/08/19 14:12
字数 2306
阅读 84
收藏 1

Hystrix Logo,不是小刺猬,更不是小浣熊,是小豪猪

一、前言

这些年分布式系统的规模和复杂度不断增加,随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中,熔断、隔离、降级是经常被使用的。而相关的技术,如 Hystrix,便成为这些年的热门技术。

从去年初开始,我所在的技术团队便开始使用 Hystrix,以实现熔断降级的设计,从而提高了系统的可用性。但由于各种原因,比如不断的新需求新功能、系统的进一步拆分、人员的流动等等。整个系统的可用性还远未达到理想状态。

虽然内部培训不断,但是具体到落地实施,单靠口头培训是远远不够的。还需要白纸黑字,方能真正达到落地的目的。这也是我写此文章的原因。

虽然 Hystrix 有着详细的官方文档,但还不足以涵盖所有使用经验、注意事项、最佳实践等方面的内容。另外语言也是另一个原因,需要考虑到会有很多开发人员不善英语的现实。

本文面向在后端应用开发有一定经验,在高可用设计方面有基本认识的软件开发从业人员。

本系列的目录

本系列后续的文章将从如下几点介绍 Hystrix:

  • 基本使用(本文)
  • 高级使用
  • 内部原理
  • 配置调优
  • 失败策略
  • 动态配置
  • 监控报警
  • 请求合并
  • 请求缓存

可能具体的内容和章节顺序还会调整。

本章内容

本章将会介绍 Hystrix 的基本使用方式和基本配置,对于 Hystrix 有相当经验的同学可以选择直接跳过。

看完本章之后,可以使用 Hystrix 实现基本的熔断设计,以保护应用的安全,实现初步的高可用设计。

二、什么是 Hystrix

虽然关于 Hystrix 的文章现在也是能经常见到,Hystrix 本身早已算不上什么新技术,但还是要简单介绍一下。

Hystrix 是一个在调用端上,实现断路器模式,以及隔舱模式,通过避免级联故障,提高系统容错能力,从而实现高可用设计的一个 Java 类库。

上面这段介绍是我的一个简要总结。更具体的介绍可以参照官网

三、Hystrix 的基本使用

Hystrix 的主要目的是保护跨进程调用,避免因为超时等问题,导致的级联故障。Hystrix 的实现方法是封装跨进程调用。具体的使用方式有多种:从编程方式看可分为编程方式和注解方式两种;从调用方式看可分为同步调用方式、异步调用方式和反应式调用方式三种。

我们先来看最常见的同步编程方式:

代码示例

@Component
public class AuthService {
  @Autowired
  private UserService userService;

  public boolean validateUser(String userId) {
    User user = new GetUserCommand(userId).execute(); // 6
    if (user == null) {
      return false;
    } else {
      return user.isValid();
    }
  }

  class GetUserCommand extends HystrixCommand<User> { // 1
    private Long userId;

    public GetUserCommand(Long userId) { // 2
      super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService")) // 3
          .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
              .withCoreSize(20) // 3
          )
          .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
              .withExecutionTimeoutInMilliseconds(100) // 3
          )
      );
      this.userId = userId;
    }

    @Override
    public User run() throws Exception {
      return userService.getUserById(userId); // 4
    }

    @Override
    public User getFallback() {
      return new InvalidUser(); // 5
    }
  }
}

代码解释

  1. Hystrix 常见的使用方法是在一个业务处理类(在本例中是 AuthService)新建一个内部类(本例中是 GetUserCommand)。这个内部类需要扩展 HystrixCommand。之所以使用内部类是因为 Hystrix 通常用来封装一次远程调用,一般直接调用一个业务方法。这个业务方法通常位于一个业务处理类或这个业务处理类所依赖的类中。而使用内部类的方式可以简化这种调用。扩展 HystrixCommand 还需声明一个泛型类型,这个泛型类型表示这个 HystrixCommand 的返回值。
  2. 定义一个 HystrixCommand 还需定义一个构造函数。这个构造函数十分重要,因为在使用这个 HystrixCommand 时,需要通过构造函数传递参数。
  3. 在构造函数中,需要调用父构造函数对当前的 HystrixCommand 进行配置。主要的配置主要有三个:GroupKey、ThreadPoolSize 和 Timeout。具体的配置方式有多种,较常用的一种方式是通过一个名为 Setter 的 Builder 类进行配置。
    1. GroupKey 通过 Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService")) 语句进行配置;
    2. ThreadPoolSize 通过 .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20)) 语句进行配置;
    3. Timeout 通过 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100) 语句进行配置;
  4. 通过实现 run() 方法,在其中实现业务逻辑。通常是调用外部类的方法或外部类依赖的方法。
  5. 通过实现 getFallback() 方法,实现失败逻辑,可以在其中实现降级等功能。
  6. 编写完 GetUserCommand 之后,使用的时候每次都需要 new 一个新对象,再调用 execute() 方法。注意,不要调用 run() 方法,否则熔断、隔离等功能是不生效的。

四、Hystrix 的基本配置

上面的部分介绍了 HystrixCommand 的基本使用方法,但只是简单介绍了几个配置。所以,下面将对 HystrixCommand 的相关配置的作用做一个较为详细的介绍。

配置模式

Hystrix 的配置有三个维度:全局默认配置、Instance 默认配置、Instance 动态配置。除了少部分配置项外,大部分配置都支持动态修改。接下来介绍一下一些主要参数的 Instance 默认配置方式。这种配置方式也是使用 Hystrix 最先接触到的配置方式。

Command Group

GroupKey 是 HystrixCommand 不可缺少的配置,其它配置均为可选。所以,使用 Hystrix 可以使用下面的代码:

public class CommandHelloWorld extends HystrixCommand<String> {
  private final String name;

  public CommandHelloWorld(String name) {
    super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
    this.name = name;
  }

  @Override
  protected String run() {
    return "Hello " + name + "!";
  }
}

HystrixCommandGroupKey 是一个接口,所以除了可以使用 HystrixCommandGroupKey.Factory.asKey("ExampleGroup") 的方式定义以外,也可以直接实现这个接口。比如使用如下的方式:

public enum Groups implements HystrixCommandGroupKey {
  GROUP_1
}

class EnumGroupCommand extends HystrixCommand<String> {
  EnumGroupCommand() {
    super(Groups.GROUP_1);
  }

  @Override
  protected String run() throws Exception {
    LOGGER.info("Thread of Command: {}", Thread.currentThread().getName());
    return null;
  }
}

如上面代码这样,使用自定义的枚举类,实现 HystrixCommandGroupKey 接口,可以统一 Hystrix Command Group 的定义,简化配置。

HystrixCommandGroupKey 的作用主要有两个:

  1. 一是起到分组监控、报警的作用。后面的文章会对监控等方面进行介绍;
  2. 二是在不配置 HystrixThreadPoolKey 的情况下,起到分组线程池的作用。即默认使用 HystrixCommandGroupKey 去命名线程池。使用同一个 HystrixCommandGroupKey 且没有自定义 HystrixThreadPoolKeyHystrixCommand 将使用同一个线程池。

Command Thread-Pool

虽然 HystrixCommandGroupKey 可以起到隔离线程池的作用,但是无法起到对线程池进行精细配置的作用。所以这里就需要线程池进行配置:

Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyService"))
    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool"))
    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
        .withCoreSize(10)
        .withKeepAliveTimeMinutes(1)
        .withMaxQueueSize(-1)
    )
)

andThreadPoolPropertiesDefaults 配置中的数值表示的是默认值。接下来逐项介绍:

  1. andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool")) 这是配置 ThreadPoolKey。如果需要在同一个 GroupKey 下面配置不同的 ThreadPool 就需要这个配置。
  2. withCoreSize(10) 用来配置线程池大小。Hystrix 对线程池的配置有一些限制,这里只能配置线程数的 Core Size,不能配置 Max Size。不配置的话使用的默认值是 10。
  3. withKeepAliveTimeMinutes(1) 用来配置核心线程数空闲时 keep alive 的时长,默认为 1 mins。这项配置一般不需要修改。
  4. withMaxQueueSize(-1) 用来配置线程池任务队列的大小,默认值为 -1。当使用 -1 时,SynchronousQueue 将被使用,即意味着其实这个队列只是一个交换器,任务将被直接交给工作线程处理。如果工作线程不足,那任务将被拒绝;如果使用任何正整数,LinkedBlockingQueue 将被使用。

Command Properties

这部分是和命令执行直接相关的配置,包括隔离策略、超时时间、Fallback 相关配置。接下来介绍几个主要的配置:

隔离策略

默认的隔离策略是实现线程池隔离,另外一种隔离策略是 Semaphore。Instance 默认配置可使用如下方法设置:

HystrixCommandProperties.Setter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)

这项配置通常不用配置

超时时间

默认时间是1s,单位是毫秒。Instance 默认配置可以使用如下方法设置:

.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100))

这项配置比较重要,后文还会详细介绍如何调配这个参数。

Fallback 并发度

在 Instance 默认配置中是通过如下代码设置的:

super(Setter.withGroupKey(BASIC_USAGE_GROUP)
    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
        .withFallbackIsolationSemaphoreMaxConcurrentRequests(10)
    )
);

默认值为 10。因为 getFallback() 方法是和 run() 方法使用同一个线程池执行的,并发过高会影响主逻辑的执行,所有需要控制并发量。如果 getFallback() 执行速度很快,那不用修改此值。如果 getFallback() 中执行一个较为耗时的操作,那就需要考虑修改此值。

参考

代码

本文所使用的示例代码可以在这里找到。

文章

© 著作权归作者所有

编走编想
粉丝 152
博文 129
码字总数 112781
作品 0
海淀
程序员
私信 提问
Spring Cloud Alibaba迁移指南2:一行代码从Hystrix迁移到Sentinel

本文对Hystrix、Resilience4j、Sentinel进行对比,并探讨如何使用一行代码将Hystrix迁移到Sentinel。 作者:洛夜,校对:周立 在本博客首发,欢迎转载。 前段时间,Netflix宣布Hystrix进入维...

周立_ITMuch
01/28
1K
7
SpringCloud之断路器聚合监控(Hystrix Turbine)

一、Hystrix Turbine简介 看单个的Hystrix Dashboard的数据并没有什么多大的价值,要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。Hystrix Turbine将每个服务Hystrix Das...

明理萝
2018/09/06
105
1
史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine)

转载请标明出处: http://blog.csdn.net/forezp/article/details/70233227 本文出自方志朋的博客 上一篇文章讲述了如何利用Hystrix Dashboard去监控断路器的Hystrix command。当我们有很多个...

forezp
2017/04/18
0
0
史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine)(Finchley版本)

上一篇文章讲述了如何利用Hystrix Dashboard去监控断路器的Hystrix command。当我们有很多个服务的时候,这就需要聚合所以服务的Hystrix Dashboard的数据了。这就需要用到Spring Cloud的另一...

灌南高手No1
2018/10/16
0
0
Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel

本文对Hystrix、Resilience4j、Sentinel进行对比,并探讨如何使用一行代码这种极简的方式,将Hystrix迁移到Sentinel。 Hystrix 自从前段时间 宣布停止维护之后,社区推荐了 resilience4j。这...

中间件小哥
02/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

堆”和“栈

C++作为一款C语言的升级版本,具有非常强大的功能。它不但能够支持各种程序设计风格,而且还具有C语言的所有功能。我们在这里为大家介绍的是其中一个比较重要的内容,C++内存区域的基本介绍。...

SibylY
37分钟前
4
0
总结:Https

一、介绍 简单理解,https即在http协议的基础上,增加了SSL协议,保障数据传输的安全性。 它由以前的http—–>tcp,改为http——>SSL—–>tcp;https采用了共享密钥加密+公开密钥加密的方式 ...

浮躁的码农
40分钟前
6
0
数据库表与表之间的一对一、一对多、多对多关系

表1 foreign key 表2 多对一:表 1 的多条记录对应表 2 的一条记录 利用foreign key的原理我们可以制作两张表的多对多,一对一关系 多对多: 表1的多条记录可以对应表2的一条记录 表2的多条记...

Garphy
今天
7
0
MySQL 表崩溃修复

MySQL日志报错 2019-10-19 13:41:51 19916 [ERROR] /usr/local/mysql/bin/mysqld: Table './initread_hss/user_info' is marked as crashed and should be repaired2019-10-19 13:41:51 1......

雁南飞丶
今天
6
0
Error和Exception

1.Error类和Exception类都是继承Throwable类 2.Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问...

大瑞清_liurq
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部