Hystrix源码:配置

自闭症网瘾萝莉.ら 提交于 2020-02-26 10:33:21

1. 配置介绍

Hystrix配置主要是为command设置各个属性的值,在Configuration中可以看到所有的属性。

每个command的属性的名字为由四部分组成:<prefix>.command.<commandKey>.<属性名>

  • prefix,属性前缀,默认hystrix
  • commandKey,command名,默认是当前类名
  • 属性名,就是上面链接中各个属性的名称,写死的

比如commandKey为test的execution.isolation.strategy属性名为hystrix.command.test.execution.isolation.strategy,这个名字一般没有什么用,但是要修改command某个属性值的时候需要知道该名字,后面会讲到。

除了commandKey,还有一个commandGroupKey,并且commandGroupKey是生成command时必填的,commandGroupKey的作用是聚合同一个group下的command数据,用于在dashboard上显示。

commandGroupKey,commandKey都相同的command,共享同一个全局配置,包括统计metric的滑动数组。

2. 两种使用方式对比

使用Hystrix主要有两种方式:加注解,继承HystrixCommand。这两种方式有各自的优缺点,对比如下。

2.1 注解方式

12345678
(groupKey = "test", commandProperties = {        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000")})public List<User> (List<String> ids) {    List<User> users = new ArrayList<User>();        return users;}

优点:对业务系统侵入性较小,只需要加一个注解
缺点:相关参数没法动态修改

2.2 继承方式

123456789101112131415
public class CommandHelloWorld extends HystrixCommand<String> {    private final String name;    public CommandHelloWorld(String name) {        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(name))          .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)));        this.name = name;    }    @Override    protected String run() {        return "Hello " + name + "!";    }}

优点:参数可以在构造方法里设置,也就是可以从配置中心中获取,动态设置
缺点:对业务系统侵入性太大,需要继承HystrixCommand

2.3 有没有综合两者优点的方法?

能不能即用注解,又能够动态调整参数?

123
HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), "unitTestPrefix");assertEquals(false, properties.circuitBreakerForceClosed().get());ConfigurationManager.getConfigInstance().setProperty("unitTestPrefix.command.default.circuitBreaker.forceClosed", true);

通过ConfigurationManager可以在运行时调整参数,ConfigurationManager这个类并不是Hystrix自身的,而是 archaius 中的,archaius也是由Netflix开发的,用来实现动态配置的,而archaius又是基于 Apache Commons Configuration ,所以要弄清楚Hystrix的动态配置,需要先了解这两个类库的使用。

3. 动态配置实现

3.1 Apache Commons Configuration

Java中自带的读取配置的类是Properties,但是这个类功能太弱,只能从文件中读,而且配置都是String类型的,Commons Configuration是对Properties的扩展,不仅能从多种数据源(文件,数据库,网络等)中读取配置,还支持配置的类型,而且还可以配置listener来监听配置的修改。

下面的例子用的版本是1.8。

12345678910111213141516171819202122232425262728
// properties配置PropertiesConfiguration propertiesConfig = new PropertiesConfiguration("test.properties");System.out.println(propertiesConfig.getString("app")); // testconfig 0.1System.out.println(propertiesConfig.getInt("i")); // 100System.out.println(propertiesConfig.getList("l")); // [s1, s2, s3, s4]// xml配置XMLConfiguration xmlConfig = new XMLConfiguration("test.xml");System.out.println(xmlConfig.getString("meta.default")); // 3System.out.println(xmlConfig.getProperty("bean.background")); // [#000000, #111111, #222222]System.out.println(xmlConfig.getString("bean(0).background")); // #000000 // 合并多个配置CompositeConfiguration comConfig = new CompositeConfiguration();comConfig.addConfiguration(propertiesConfig);comConfig.addConfiguration(xmlConfig);System.out.println(comConfig.getList("l")); // [s1, s2, s3, s4] // 直接将配置映射为beanBeanDeclaration decl = new XMLBeanDeclaration(xmlConfig, "testbean");Bean bean = (Bean) BeanHelper.createBean(decl);System.out.println(bean.getName()); // beanname// 监听配置修改propertiesConfig.addConfigurationListener(event -> {    System.out.println("name:" + event.getPropertyName() + ", value:" + event.getPropertyValue()); // name:i, value:100});propertiesConfig.setProperty("i", 100);
1234
@Datapublic class Bean {    String name;}
123456789101112
# test.properties# 占位符name=testconfigversion=0.1app=${name} ${version}大专栏  Hystrix源码:配置omment"># 引入其他配置include = test1.properties# 数组l = s1, s2, s3l = s4
12
# test1.propertiesi=100
1234567891011121314151617181920
<?xml version="1.0" encoding="ISO-8859-1" ?><!--test.xml--><colors>    <meta>        <num>3</num>        <default>${meta.num}</default>    </meta>    <bean>        <background>#000000</background>    </bean>    <bean>        <background>#111111</background>    </bean>    <bean>        <background>#222222</background>    </bean>    <testbean config-class="testapacheconfig.Bean" name="beanname">    </testbean></colors>

3.2 archaius

Commons Configuration看起来功能足够了,为什么archaius还会出现呢?主要是因为Commons Configuration并不是线程安全的,所有配置从文件读取后放在一个LinkedHashMap中,archaius在其基础上实现了线程安全,并且对配置的类型支持的更好。

12345678910
PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration("test.properties");ConfigurationManager.install(propertiesConfiguration);System.out.println(ConfigurationManager.getConfigInstance().getString("app")); // testconfig 0.1 DynamicStringProperty stringProperty = DynamicPropertyFactory.getInstance().getStringProperty("app", "");System.out.println(stringProperty); // DynamicProperty: {name=app, current value=testconfig 0.1}ConfigurationManager.getConfigInstance().setProperty("app", "modify");System.out.println(ConfigurationManager.getConfigInstance().getString("app")); // modify System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("app", "")); // DynamicProperty: {name=app, current value=modify}

使用archaius时一般不会直接和Configuration类交互,而是和DynamicXXXProperty交互,DynamicXXXProperty中XXX就是配置的类型,如果要修改配置的话,仍然需要通过Configuration来做。

archaius源码中有几个比较重要的类:ConfigurationBackedDynamicPropertySupportImpl,DynamicProperty,PropertyWrapper。

  • ConfigurationBackedDynamicPropertySupportImpl是沟通common config中Configuration和archaius中的DynamicXXXProperty的桥梁,从DynamicXXXProperty的数据来源于Configuration,并且Configuration中的配置修改了,DynamicXXXProperty对应的值也会修改,就是通过Configuration的listener来实现的。
  • DynamicProperty是archaius实现配置类型的核心,内部的ALL_PROPS放置了所有的DynamicXXXProperty。
  • PropertyWrapper只是包装了一下DynamicProperty,用于通过DynamicProperty实现不同类型的配置。

在翻archaius源码的过程中,感觉它的实现并不好,Configuration中维护了一套配置,DynamicXXXProperty中又维护了一套配置,两个配置是等价的,每次修改Configuration时,需要同时修改DynamicXXXProperty。

3.3 Hystrix的插件式配置

archaius的功能基本上是能够满足Hystrix的,即线程安全,性能也比较好,但是Hystrix并没有直接使用archaius,而是又在archaius的基础上包装了一下,主要原因是Hystrix希望将配置做成插件式的,配置的提供者不限于archaius,可以是任何满足条件的类。

3.3.1 相关接口

其中涉及到的接口主要有:HystrixDynamicProperties,HystrixProperty,HystrixDynamicProperty。

  • HystrixDynamicProperties是Hystrix自身提供的一套配置规范,只要实现这个接口,就可以向Hystrix提供配置,比如如果不想从archaius读配置,可以自己实现一套从zk等其他地方读配置的方式,实现完了后如何将这个实现插入Hystrix会在后面说明。
  • HystrixProperty和HystrixDynamicProperty和archaius的DynamicProperty一样的作用,只是Hystrix没用DynamicXXXProperty这些类,而是自己重新弄了一套,为了将具体配置的实现独立出去。

3.3.2 搜索配置插件过程

在HystrixPlugins初始化时就会搜索配置插件,具体过程在resolveDynamicProperties方法中:

12345678910111213141516171819202122232425262728
private static HystrixDynamicProperties resolveDynamicProperties(ClassLoader classLoader, LoggerSupplier logSupplier) {    HystrixDynamicProperties hp = getPluginImplementationViaProperties(HystrixDynamicProperties.class,             HystrixDynamicPropertiesSystemProperties.getInstance());    if (hp != null) {        logSupplier.getLogger().debug(                "Created HystrixDynamicProperties instance from System property named "                + ""hystrix.plugin.HystrixDynamicProperties.implementation". Using class: {}",                 hp.getClass().getCanonicalName());        return hp;    }    hp = findService(HystrixDynamicProperties.class, classLoader);    if (hp != null) {        logSupplier.getLogger()                .debug("Created HystrixDynamicProperties instance by loading from ServiceLoader. Using class: {}",                         hp.getClass().getCanonicalName());        return hp;    }    hp = HystrixArchaiusHelper.createArchaiusDynamicProperties();    if (hp != null) {        logSupplier.getLogger().debug("Created HystrixDynamicProperties. Using class : {}",                 hp.getClass().getCanonicalName());        return hp;    }    hp = HystrixDynamicPropertiesSystemProperties.getInstance();    logSupplier.getLogger().info("Using System Properties for HystrixDynamicProperties! Using class: {}",             hp.getClass().getCanonicalName());    return hp;}

顺序为:

  1. System property中找key为hystrix.plugin.HystrixDynamicProperties.implementation的配置
  2. 通过spi找HystrixDynamicProperties的实现,即读取META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties文件
  3. 创建HystrixDynamicPropertiesArchaius实例,使用archaius作为配置源
  4. 创建HystrixDynamicPropertiesSystemProperties实例,从System property中读配置

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!