Hystrix 基本用法以及如何进行动态配置更新

Hystrix

Hystrix 是 Netflix 开源的一个限流熔断降级组件,防止依赖服务发生错误后,将调用方的服务拖垮。这里对 Hystrix 本身不做过多介绍。

Hystrix 目前处于维护状态(不再更新),但是还有大量项目对它进行了使用,因此仍然非常重要。

基本用法

在 Hystrix 中,HystrixCommand 是非常重要的一个类,用于对目标服务进行保护。

在 Hystrix 的基本用法中:

  • 首先,我们需要创建一个自定义类 CustomHystrixCommand 来继承 Hystrix 提供的 HystrixCommand 类。
  • 然后,每次调用服务的时候,我们需要创建一个 CustomHystrixCommand 实例,将调用的逻辑封装在该 Command 之内,然后 Hystrix 就会帮我们根据配置,自动对系统进行保护,在适当的时候进行限流、熔断降级的操作。

例如,在 Hystrix 官方文档 中有个很简单的 Hello World 例子:

首先,创建自定义类 CommandHelloWorld

public class CommandHelloWorld extends HystrixCommand<String> {

    private final String name;

    public CommandHelloWorld(String name) {
    	// 这里是当前 Command 的配置信息
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }

    @Override
    protected String run() {
        // a real example would do work like a network call here
        return "Hello " + name + "!";
    }
}

如果需要调用,则直接执行

String s = new CommandHelloWorld("World").execute();

就可以了。

如何使用配置

作为熔断和降级的组件,Hystrix 当然必须提供一些配置,例如:在多少秒内服务异常次数超过多少次时,会触发熔断,以及熔断多少秒后,重新尝试请求服务,等等。

这些配置决定了 Hystrix 该如何工作,我们可以在 HystrixCommand 的构造过程中,对这些配置进行修改(当然,不修改的话,也是有默认配置的)。为了达成以上目的,Hystrix 需要在服务的维度上,记录时间、请求数量、是否错误等信息,从而使自己有足够的信息来判断是否应该熔断。

上面提到服务的维度,那么 Hystrix 是如何区分服务的呢?

在 Hystrix 中有两个用于对服务进行命令和区分的配置:Group key 和 Command key,分别可以理解为组关键字和命令关键字,一个组关键字中可以有多个命令关键字。

例如,可以将上面 CommandHello 中的构造函数修改为:

    public CommandHelloWorld(String name) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")));
        this.name = name;
    }

其中 Setter 中就指定了当前命令的组关键字和命令关键字。

当然,上面提到的熔断等,也是可以在这个 Setter 里面进行配置的。

    public CommandHelloWorld(String name) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
                .andCommandPropertiesDefaults(propSetter)); // 这里配置熔断等的信息
        this.name = name;
    }

这里的 propSetter 是一个 HystrixCommandProperties.Setter 类的字段,其中包含了熔断等的配置,这里就不过多展开了,感兴趣的可以直接看这个类的源码。

动态配置更新的问题

什么是动态配置更新?即在应用程序运行时,对熔断等配置进行动态修改,并使得修改可以立即生效。

举个例子,对于一个服务,我本来配置的是 60s 内有 3 次请求出错就熔断,现在我想改成 20s 内有 5 次请求出错才熔断,并且需要该修改立即生效,那么 Hystrix 可以做到吗?

首先给出结论:Hystrix 可以做到。按照官方的说法,Hystrix 支持使用 Archaius 进行动态配置,详情可见 https://github.com/Netflix/Hystrix/wiki/Configuration#intro

但是,这种用法需要 Archaius 进行配合,如果在生产环境中使用,那你又要引入一个新的依赖组件 Archauis,未免有点得不偿失了。那么我们有没有办法在不引入任何新的组件前提下,从代码的角度上实现配置动态更新呢?

答案是可以的,只是需要一些骚操作。仅仅修改 HystrixCommand 构造时 Setter 里面的 CommandPropertiesDefaults 里的熔断配置,是没有用的!

那么为啥仅修改以上配置没用呢?这里涉及了 Hystrix 里两个地方,使用了缓存,导致动态修改无法生效,仍然会使用缓存的值(也就是修改之前的值)。这两个缓存分别为:

  • HystrixPropertiesFactory 里面的 commandProperties 字段,这里存储了HystrixCommand 的基本属性。
  • HystrixCircuitBreaker$Factory 里面的 circuitBreakersByCommand 字段,这里存储了 HystrixCommand 的熔断器(用于判断何时熔断以及打开/关闭熔断)。

这两个字段都是 ConcurrentHashMap 类型,其 key 为 HystrixCommand 的 commandKey。我们知道 commandKey 一般会设置为服务名称,那么也就是说:对于同一个服务,即使修改了其熔断配置,仍然会因为缓存原因,使用修改之前的配置以及熔断器,那么动态更新就无法生效了。

如何解决

找到了缓存的位置,也就找到了动态配置更新不生效的根本原因,接下来去解决就好了,解决思路很直接:当检测到配置发生改变时,主动删掉缓存 Map 中的相关项。

但是,Hystrix 似乎并没有考虑动态配置更新这一需求,以上两个缓存使用的 Map,都是静态私有字段,我们在外部理论上是不能获取并修改它们的。。

如何解决?实际也很简单,利用反射即可,我们知道利用反射可以访问到类的私有字段/方法,那么问题就可以解决了。

例如,对于 HystrixCircuitBreaker$Factory 里的 circuitBreakersByCommand ,可以使用以下方式进行缓存项清除:

try {
    Field field = HystrixCircuitBreaker.Factory.class.getDeclaredField("circuitBreakersByCommand");
    field.setAccessible(true);
    // 由于是 static 字段,直接 get(null) 即可
    ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand = (ConcurrentHashMap<String, HystrixCircuitBreaker>) field.get(null);
    // 这里 commandKey 就是待更新的服务名
    circuitBreakersByCommand.remove(commandKey);
} catch (NoSuchFieldException | IllegalAccessException e) {
    log.error("Remove cache in HystrixCircuitBreaker.Factory failed, commandKey: {}", commandKey, e);
}

至于另一个缓存项,也是同样的方法,这里就不赘述了。

总之,注意以上两个地方的缓存,就可以使得 Hystrix 具备动态配置更新的能力了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hystrix是一个用于处理分布式系统间的错误和延迟的库。它提供了一些机制来保护你的系统免受故障的影响,并且帮助你优雅地处理这些故障。 以下是使用Hystrix的步骤: 1. 添加依赖 在你的项目中添加Hystrix的依赖,例如: ```xml <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.18</version> </dependency> ``` 2. 定义命令 Hystrix的核心是命令模式。你需要定义一个继承自HystrixCommand的类,例如: ```java public class MyCommand extends HystrixCommand<String> { private final String name; public MyCommand(String name) { super(HystrixCommandGroupKey.Factory.asKey("MyGroup")); this.name = name; } @Override protected String run() throws Exception { // Do something that might fail return "Hello, " + name; } @Override protected String getFallback() { return "Fallback"; } } ``` 在这个例子中,我们定义了一个MyCommand类,它接收一个字符串作为参数,并返回一个字符串。在run()方法中,我们可以执行一些可能失败的操作,并在getFallback()方法中定义降级逻辑。 3. 执行命令 执行MyCommand命令的代码如下: ```java String result = new MyCommand("World").execute(); ``` 这将执行MyCommand命令,并返回结果。如果命令执行失败或超时,Hystrix将触发降级逻辑并返回fallback值。 4. 配置Hystrix 你可以使用Hystrix配置来调整不同参数的值,例如: ```java HystrixCommandProperties.Setter() .withExecutionTimeoutInMilliseconds(1000) .withCircuitBreakerRequestVolumeThreshold(10) .withCircuitBreakerErrorThresholdPercentage(50) .withCircuitBreakerSleepWindowInMilliseconds(5000) ``` 这些配置参数可以控制Hystrix的行为,例如设置命令的超时时间、熔断器的触发条件等。 以上就是使用Hystrix基本流程,你可以根据自己的需求来使用Hystrix来保护你的分布式系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值