前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[享学Netflix] 十八、Hystrix配置之:全局配置和实例配置

[享学Netflix] 十八、Hystrix配置之:全局配置和实例配置

作者头像
YourBatman
发布2020-03-18 19:22:49
2.5K0
发布2020-03-18 19:22:49
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦

今天,多少孩子既要美国式的自由,又要中国式的宠爱。却没有美国孩子的独立,却又失去了中国传统的孝道。 代码下载地址:https://github.com/f641385712/netflix-learning

目录
  • 前言
  • 正文
    • HystrixPropertiesChainedProperty.ChainBuilder
      • 使用示例
    • HystrixKey
      • HystrixCommandGroupKey
    • HystrixCommandProperties
      • 全局配置和实例配置
        • 特殊案例说明
      • Setter
      • 其它xxxProperties
      • 使用示例
  • 总结
    • 声明

前言

上篇文章介绍了HystrixArchaius的整合,对深入了解Hystrix内部的属性配置打好了基础。对于属性配置,程序员们的感受可能是可能既爱又恨,因为那些浩如烟海的配置项确实可能已经超过了你的脑容量。

但越是这样的工作,就越不可能靠强记的,而是应掌握其规律,学会查“字典”才是永恒之道。Hystrix的属性配置不在少数,但它管理得非常的好,因此本文将从全局配置和实例配置作为切入点,授之以渔帮小伙伴们从根本上掌握Hystrix的配置相关知识点。


正文

配置虽不可或缺,但也切勿让繁杂的配置扰乱了你的心智,所以从根本上找到管理配置的规律,将为你编码、调优过程大大减负。


HystrixPropertiesChainedProperty.ChainBuilder

在正式接触Hystrix的配置管理类之前,有必要先对基础支撑组件做些了解。

ChainBuilder用于快速构建一个HystrixDynamicProperty实例。上篇文章已经说过HystrixDynamicProperty的实例均以匿名方式实现,并没有可以给你直接使用的实例。因此若你想在“外部”需要构建它,还得自己写个实现类着实麻烦,因此就有了本构建器来帮你解决难题。

它是HystrixPropertiesChainedProperty的一个静态public内部类:

代码语言:javascript
复制
HystrixPropertiesChainedProperty:

	public static abstract class ChainBuilder<T> {
		// 构建所需的所有的动态属性们
        private List<HystrixDynamicProperty<T>> properties =  new ArrayList<>();

		// 添加一个动态属性property
        public ChainBuilder<T> add(HystrixDynamicProperty<T> property) {
            properties.add(property);
            return this;
        }
        // 这里最重要的方法是:getDynamicProperty(),它会自己动态去获取
        // 另外注意:这个getType是个抽象方法~~~~
        public ChainBuilder<T> add(String name, T defaultValue) {
            properties.add(getDynamicProperty(name, defaultValue, getType()));
            return this;
        }
        protected abstract Class<T> getType();

		// 构建
		// 简单的说:若properties这个List一个值都木有,就抛错
		// 若只有一个值,那便是它
		// 若有多个值(比如你add了多次),那就按照你add的顺序,以第一个不为null的为准
		public HystrixDynamicProperty<T> build() {
			...
		}

	}

	
	// HystrixPlugins.getInstance().getDynamicProperties()
	// 这句最终得到的是一个`HystrixDynamicPropertiesArchaius`,也就是从全局的Configuration去获取值
    private static <T> HystrixDynamicProperty<T> getDynamicProperty(String propName, T defaultValue, Class<T> type) {
        HystrixDynamicProperties properties = HystrixPlugins.getInstance().getDynamicProperties();
        HystrixDynamicProperty<T> p = HystrixDynamicProperties.Util.getProperty(properties, propName, defaultValue, type);
        return p;
    }

使用它,不仅可以快速构建出一个HystrixDynamicProperty动态属性实例,而且还能和全局的Configuration完成整合,并且控制add()的优先级,功能还是挺强大的,推荐使用。

ChainBuilder自己是个抽象类,那么如何构建它呢?这里提供有4个static工具方法供以使用:

代码语言:javascript
复制
HystrixPropertiesChainedProperty:

    public static ChainBuilder<String> forString() {
        return forType(String.class);
    }
    public static ChainBuilder<Integer> forInteger() {
        return forType(Integer.class);
    }
    public static ChainBuilder<Boolean> forBoolean() {
        return forType(Boolean.class);
    }
    public static ChainBuilder<Long> forLong() {
        return forType(Long.class);
    }    

使用示例
代码语言:javascript
复制
@Test
public void fun2() {
    HystrixDynamicProperty<String> property = HystrixPropertiesChainedProperty.forString()
            .add("hystrix.command.myApp.personName", null)
            .add("hystrix.command.default.personName", "name-default")
            .build();
    System.out.println(property.get());
}

配置书写在config.properties里,这段代码会根据配置的不同而结果不同:

  1. 不写任何配置,输出:name-default
    1. 注意:因为第一个add()最终值是null(不管是获取,还是默认值均为null嘛),所以就以第二个值为准啦
  2. 书写配置如下,输出:James
代码语言:javascript
复制
hystrix.command.myApp.personName=James
hystrix.command.default.personName=Bryant
  1. 书写配置如下,输出:Bryant
代码语言:javascript
复制
hystrix.command.default.personName=Bryant

这段示例代码,便是Hystrix实现动态配置,并且实现全局 + 实例配置相结合的缩影。

说明:Hystrix为几乎所有的key,即可配置一个全局配置,又可以单独为某个HystrixCommand单独配置一个个性化数值,弹性非常强


HystrixKey

一个接口,代表Hystrix的一个key。

代码语言:javascript
复制
public interface HystrixKey {

	// “name”这个词代替了“key”,这样enum就可以实现这个接口,并且它可以本地工作。
	// 所以这个考量其实还蛮巧妙的,考虑挺周全
	String name();
}

这个接口极其简单,它有如下实现类:

在这里插入图片描述
在这里插入图片描述

先看Default默认实现:

代码语言:javascript
复制
HystrixKey:

	// 注意:它还是个抽象类呢(当然接口内的肯定是static喽)
    abstract class HystrixKeyDefault implements HystrixKey {
        private final String name;
        public HystrixKeyDefault(String name) {
            this.name = name;
        }
        @Override
        public String name() {
            return name;
        }
        @Override
        public String toString() {
            return name;
        }
    }

这个抽象默认实现就太简单了,其它实现也均继承于它。


HystrixCommandGroupKey

HystrixKey的子接口。表示HystrixCommand的组名,用于将报告、告警、仪表盘dashboards等等信息分组放在一起。

代码语言:javascript
复制
// 该接口木有任何新增方法,只是提供了一个内部Factory类
public interface HystrixCommandGroupKey extends HystrixKey {

	// 接口内部类
	class Factory {

		// 用于intern缓存HystrixCommandGroupDefault实例
		// 这样我们就不会为了同一个键重复创建它们数百万次,提高效率
		// InternMap它就是一个Map,内部持有ConcurrentHashMap用作缓存使用~
		// 这样:每一个String类型的key,调用interned()方法后就会被缓存进Map里~~~
		// 注意:这个只是私有方法,供内部方法使用
		private static final InternMap<String, HystrixCommandGroupDefault> intern = new InternMap<>(key -> new HystrixCommandGroupDefault(key));

		// 根据一个字符串的key,得到一个HystrixCommandGroupKey实例
        public static HystrixCommandGroupKey asKey(String name) {
           return intern.interned(name);
        }

		// 私有,私有静态内部类实现HystrixCommandGroupKey 接口~~~
		// 注意:该类私有,外部并不能访问和构造
        private static class HystrixCommandGroupDefault extends HystrixKey.HystrixKeyDefault implements HystrixCommandGroupKey {
            public HystrixCommandGroupDefault(String name) {
                super(name);
            }
        }
        // 获取key的总数
		static int getGroupCount() {
            return intern.size();
        }
	}
}

此接口内聚性非常高:外部可访问的只能是接口,实现类都放在了内部,并且仅仅只提供asKey()一个方法供以使用,因此使用起来也是极其方便的设计。

另外两个子接口HystrixThreadPoolKey以及HystrixCommandKey的逻辑和上面一毛一样,略过。


HystrixCommandProperties

本文将以HystrixCommandProperties为例,逐步学习Hystrix对配置的管理,掌握了它后,其它自然就触类旁通。

HystrixCommandProperties用于配置一个HystrixCommand实例的配置类,含有很多配置项,默认使用archaius管理。

代码语言:javascript
复制
public abstract class HystrixCommandProperties {
	
	... // 非常多的成员变量HystrixProperty,每个都代表着一个属性,后面会逐个解释

	// 构造器,key是必须的,其它都非必传(这个key蛮关键的)
	// 前缀均写死为:hystrix,一般也请不要改变它
    protected HystrixCommandProperties(HystrixCommandKey key) {
        this(key, new Setter(), "hystrix");
    }
    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder) {
        this(key, builder, "hystrix");
    }
    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
        this.key = key;
        // 示例一个:最大的特点是分为全局配置,和实例级别配置
        this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
        ... // 对以上所有的成员属性通过getProperty()方法赋值
        ...

		// 线程池无全局配置,只能配实例级别的
		this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();
    }
	...
	...
	... // 省略所有的成员属性的get方法

}

该抽象类集中管理了配置,并且很比较巧妙的实现了默认值、外部化、动态化配置的一体化实现。


全局配置和实例配置

Hystrix它支持全局配置和实例配置,核心处理逻辑如下代码,其中最为关键之地在于它的getProperty()这个处理方法,它会通过此方法给每个成员属性赋值。

代码语言:javascript
复制
HystrixCommandProperties:

	// 得到一个Boolean类型的ChainBuilder构建出一个属性值HystrixProperty
	// 实际build的是个HystrixDynamicProperty动态属性哦~~~~
    private static HystrixProperty<Boolean> getProperty(String propertyPrefix, HystrixCommandKey key, String instanceProperty, Boolean builderOverrideValue, Boolean defaultValue) {
        return forBoolean() // 
                .add(propertyPrefix + ".command." + key.name() + "." + instanceProperty, builderOverrideValue)
                .add(propertyPrefix + ".command.default." + instanceProperty, defaultValue)
                .build();
    }
    ... // 省略String、Integer等类型

有了文首对ChainBuilder内容的铺垫,理解这段代码就毫无障碍了,规则如下:

  • Hystrix属性配置分为全局配置实例配置
  • 全局配置作用与所有的HystrixCommand实例,而实例配置仅作用于指定名称的HystrixCommand实例(实例名称就是HystrixCommandKey key
  • 全局配置示例:hystrix.command.MyInstanceName.circuitBreaker.enabled = false
    • 此处的MyInstanceName就代表实例名称,该配置只会作用于指定的实例
  • 实例配置示例:hystrix.command.circuitBreaker.enabled = true
  • 当全局和实例配置均能在某一实例上生效时,实例配置优先级更高

特殊案例说明

有两个稍微特殊点的案例这里做特别说明。

executionIsolationThreadPoolKeyOverride

代码语言:javascript
复制
this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();

因为它不能有全局配置,所以只会有实例配置,譬如:hystrix.command.MyInstanceName.threadPoolKeyOverride = myThreadPool

executionIsolationStrategy:执行时的隔离策略。因为隔离策略只能有如下两个取值:

代码语言:javascript
复制
HystrixCommandProperties:

	// 内部静态枚举类:执行时隔离的两种策略
	// THREAD:在隔离的线程里执行run方法,并且使用线程池来限制并发的大小
	// SEMAPHORE:就在当前线程里执行run方法,但是会使用全局的Semaphore信号量来控制并发
    public static enum ExecutionIsolationStrategy {
        THREAD, SEMAPHORE
    }

所以这个配置它对value取值是有要求的:依赖于ExecutionIsolationStrategy.valueOf(value),只有它不抱错才算有效,否则配置无效会被忽略。譬如:hystrix.command.MyInstanceName.execution.isolation.strategy = SEMAPHORE是一个合法的value值~

说明:这个value值不能是小写,比如全大写。也就是说可能取值有且仅有两个:THREADSEMAPHORE,这点上Hystrix的容错性做得似乎不是特别的好~


Setter

Hystrix里大量的使用内部类Setter来表示作用于其上的配置,用户可构建它的实例而通过编码的方式自定义属性值。

在这里插入图片描述
在这里插入图片描述

HystrixCommandProperties.Setter自然也不例外,也是这个作用。

代码语言:javascript
复制
HystrixCommandProperties:

	public static class Setter {
		private Boolean circuitBreakerEnabled = null;
		...
		private ExecutionIsolationStrategy executionIsolationStrategy = null;
		...
		private Boolean requestLogEnabled = null;
		... // 省略所有get、set方法
	}

它的作用就是对外API,方便你使用API方式定制参数,形如这样使用:

代码语言:javascript
复制
@Test
public void fun4(){
    // 使用API方式定制配置
    HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter();
    setter.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
            .withExecutionTimeoutEnabled(true)
            .withExecutionTimeoutInMilliseconds(3000);

    // HystrixPropertiesStrategy
    HystrixCommandProperties hystrixProperties = new HystrixPropertiesCommandDefault(HystrixCommandKey.Factory.asKey("MyInstanceName"), setter);
    
    // ... 省略应用hystrixProperties的步骤喽~
}

一般情况下,直接使用Setter的方式极少,但是在API集成方面就必须使用到它了。例如HystrixFeign集成时,Setter就起到了配置桥梁的作用,不容忽视。


其它xxxProperties

像截图中的其它配置类,如HystrixThreadPoolPropertiesHystrixTimerThreadPoolPropertiesHystrixCollapserProperties等,原理和处理方式和上面的HystrixCommandProperties一毛一样,唯一区别就是key的中间部分不一样:

  • HystrixThreadPoolProperties:.threadpool. / .threadpool.default.
  • HystrixTimerThreadPoolProperties:.timer.threadpool.default.
  • HystrixCollapserProperties:.collapser. / .collapser.default.

其它部分此处就不做过多展开了,略。


使用示例

HystrixCommandProperties是个抽象类,并不能直接使用。像这种配置抽象类均由一个默认实现类:

代码语言:javascript
复制
public class HystrixPropertiesCommandDefault extends HystrixCommandProperties {
	// 只提供给你一个构造器,并没有想让你去自定义前缀的意思。固定值是:hystrix
    public HystrixPropertiesCommandDefault(HystrixCommandKey key, Setter builder) {
        super(key, builder);
    }
}

吐槽一句:写这个类名的那个人估计当时睡着了,HystrixPropertiesCommand是个什么鬼,命名是HystrixCommandProperties嘛~

因此,可以这么来用:

代码语言:javascript
复制
@Test
public void fun5() {
    // 请注意:这里传null会抛出异常,Hystrix很多代码的健壮性其实是非常不够的,这是它的缺点,需要批评
    // HystrixCommandProperties commandProperties = new HystrixPropertiesCommandDefault(HystrixCommandKey.Factory.asKey("myApp"), null);
    HystrixCommandProperties commandProperties = new HystrixPropertiesCommandDefault(HystrixCommandKey.Factory.asKey("myApp"), HystrixCommandProperties.Setter());

    // 很明显,这里打印的肯定就是属性的默认值喽
    System.out.println(commandProperties.circuitBreakerEnabled().get());
    System.out.println(commandProperties.executionIsolationStrategy().get());
    System.out.println(commandProperties.executionTimeoutEnabled().get());
    System.out.println(commandProperties.executionTimeoutInMilliseconds().get());
}

控制台打印:

代码语言:javascript
复制
true
THREAD
true
1000

总结

关于Netflix Hystrix配置之:全局配置和实例配置就介绍到这了。我十分相信你看完此篇文章之后,再也不会惧怕那种浩如烟海的配置了,至少不会再担心Hystrix不知道如何配了吧。

本文只讲述了Hystrix如何管理配置,以及全局配置和实例配置的优先级关系等等,但是“内容”,也就是每个配置到底什么意思,能起什么作用,这在实战中还是蛮有意义的,因此在后续文章中还会详细这块内容。虽然很麻烦,但还是得做呀~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 前言
  • 正文
    • HystrixPropertiesChainedProperty.ChainBuilder
      • 使用示例
    • HystrixKey
      • HystrixCommandGroupKey
    • HystrixCommandProperties
      • 全局配置和实例配置
      • Setter
      • 其它xxxProperties
      • 使用示例
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档