Java 程序员spring cloudJava

【微服务技术专题】Netflix动态化配置服务-微服务配置组件变

2021-08-28  本文已影响0人  马小莫QAQ

前提介绍


Archaius是什么

Netflix Archaius是一个配置管理库,其重点是来自多个配置存储的动态属性。它包括一组用于Netflix的Java配置管理API。它主要实现为Apache Commons Configuration库的扩展。提供的主要功能有:

注意,Netflix只是开源了其配置中心的客户端部分(也就是Archaius),没有开源配套的服务器端。Archaius其实是配置源实现无关的,可以对接各种配置中心作为数据源,本文后面会介绍Archaius如何和Apollo配置中心进行集成。

Archaius项目的由来

Archaius在Netflix的用例场景

  1. 根据请求上下文开启或关闭某项功能。
  2. 某个页面缺省显示10个商品,在某些情况下,可以通过Archaius调整配置,只显示5个商品。
  3. 动态调整Hystrix熔断器的行为。
  4. 调整服务调用客户端的连接和请求超时参数。
  5. 如果某个线上服务产生出错告警,可以动态调整日志输出级别(粒度可以细到包或者组件级别),这样可以通过详细日志排查问题。问题定位以后,再将日志输出级别恢复到默认级别。
  6. 对于多区域或者多国家部署的应用,通过动态配置,可以根据不同区域和国家开启不同的功能。
  7. 可以根据用户的实际访问模式动态调整一些基础中间件的配置,例如缓存的存活时间TTL(Time To Live)。
  8. 数据库访问客户端的连接池配置,可以对不同服务配不同的值。例如,一个请求频率RPS(Request Per Second)小的服务,可以配置较小的连接数,而一个请求频率大的服务,可以配置较大的连接数。
  9. 运行期配置的变更可以在不同维度生效,例如集群中的单个实例维度,多区域部署下的某个区域维度,某个服务栈维度,或者某个应用集群维度。
  10. 功能开关(Feature Flag)发布,有些功能虽然上线,但是并不马上启用,而是通过配置开关动态启用,这样可以根据情况灵活开启或者关闭某项线上功能。
  11. 金丝雀发布(Canary Release),新功能上线时,让新老集群同时并存一段时间,通过配置将到老集群的流量逐步动态调整到新集群,如果监控显示无异常,则完成新集群的上线,如异常,则快速切回老集群。

Archaius的技术基础

Archaius的架构设计

Archaius实际上是对Apache Common Configuration Library的一个封装和扩展,提供了一组基于Java的配置API,主要的特性包括:

对于愿意使用基于约定的属性文件位置的应用程序(以及大多数web应用程序),提供开箱即用的复合配置(这是强大功能之一),对于符合配置官网给了一副示例图如下:

Achaius的核心是一个称为组合配置(Composite Configuration)的概念,简单可以理解为一个分层级的配置,层级有优先级,高优先级的层级的配置会覆盖低优先级的配置。每一个层级可以从某个配置源获取配置,例如本地配置文件,JDBC数据源,远程REST API等。配置源还可以在运行时动态拉取变更,例如在上图中,持久化数据库配置(Persisted DB Configuration)是指将配置存在关系数据库中,相应的配置源会定期从数据库拉取变更)。配置的最终值由顶级配置决定,例如,如果多个层级都含有某个配置项,那么应用最终见到的值是配置层级中最顶层的值。配置分层的顺序是可以调整的。

通过archaius获取配置值,有两种方式:

Archaius的实现原理

Archaius是什么?

Archaius提供了动态修改配置的值的功能,在修改配置后,不需要重启应用服务。其核心思想就是轮询配置源,每一次迭代,检测配置是否更改,有更改重新更新配置。

底层archaius提供实现了Apache-common-configuration的AbstractConfiguration的具体实现。


ConcurrentCompositeConfiguration使用了组合模式,组合不同的AbstractConfiguration实现。对于有多个配置源的配置中心,可以使用ConcurrentCompositeConfiguration。对于同一个配置项,多个配置源都有配置值的时候,取第一个匹配到的配置源的数据。

DynamicPropertyFactory是怎么运行的?

当创建的DynamicProperty实例数量比较大的时候,这里可能有性能问题。每创建一个任何一个DynamicProperty,都会增加一个listener,同时,任何一个配置项发生变化,都会触发listener。

可能是考虑到生产环境中不会有那么多的配置项变更吧。像zk-config那种对应配置项变更才触发watcher要好一点。

AbstractConfiguration是怎么注入的?

archaius仅允许一个AbstractConfiguration的实现类。如果有多个配置源,可以使用上面提到的ConcurrentCompositeConfiguration将不同的AbstractConfiguration组合起来。

有以下几种方式注入AbstractConfiguration。
  1. 配置archaius.default.configuration.class 指定AbstractConfiguration实现类

  2. 配置 archaius.default.configuration.factory 指定AbstractConfiguration实例工厂方法类,工厂方法类需要实现getInstance方法返回AbstractConfiguration实例

  3. 调用 ConfigurationManager 的 install(AbstractConfiguration config) 方法

  4. 调用DynamicPropertyFactory 的 initWithConfigurationSource(AbstractConfiguration config) 方法

以上方法是互斥的,只能使用其中的一种,一种生效后,其他的就不能调用了。

一个简单的例子:
Maven依赖配置
<dependency>
    <groupId>com.netflix.archaius</groupId>
    <artifactId>archaius-core</artifactId>
    <version>0.7.7</version>
</dependency>
获取配置源
/**
 * Created by longfei on 17/1/19.
 *//**  
public class DynamicConfigurationSource implements PolledConfigurationSource {
    @Override
    public PollResult poll(boolean initial,Object checkPoint) throws Exception {
        Map<String,Object> map = new HashMap<>();
        map.put("test",UUID.randomUUID().toString());
        return PollResult.createFull(map);
    }
}
定义调度器
AbstractPollingScheduler scheduler = new FixedDelayPollingScheduler(2000,2000,false);
定义动态配置
DynamicConfiguration configuration = new DynamicConfiguration(source,scheduler);
简单单元测试
@org.testng.annotations.Test
    public void testArchaius() throws Exception {
        PolledConfigurationSource source = new DynamicConfigurationSource();
        AbstractPollingScheduler scheduler = new FixedDelayPollingScheduler(2000,2000,false);
        DynamicConfiguration configuration = new DynamicConfiguration(source,scheduler);
        ConfigurationManager.install(configuration);
        final DynamicStringProperty stringProperty = DynamicPropertyFactory.getInstance().getStringProperty("test","nodata");
        Helpers.subscribePrint(Observable.interval(1,TimeUnit.SECONDS).take(20).doOnNext(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        System.out.println(stringProperty.get());
                    }
                }),"test");
        TimeUnit.MINUTES.sleep(1);
    }

实现

启动轮询任务
public synchronized void startPolling(PolledConfigurationSource source, AbstractPollingScheduler scheduler) {
    this.scheduler = scheduler;
    this.source = source;
    init(source, scheduler);
    scheduler.startPolling(source, this);
}
轮询的Runnable和初始化:实现是一致的
PollResult result = null;
    try {
       result = source.poll(false,getNextCheckPoint(checkPoint));
       checkPoint = result.getCheckPoint();
       fireEvent(EventType.POLL_SUCCESS, result, null);
       } catch (Throwable e) {
       log.error("Error getting result from polling source", e);
       fireEvent(EventType.POLL_FAILURE, null, e);
       return;
       }
       try {
          populateProperties(result, config);
       } catch (Throwable e) {
           log.error("Error occured applying properties", e);
      }

注意到,会调用source.poll方法,即PolledConfigurationSource的polled,我们实现的数据源接口,可以自定义数据源(jdbc,文件,scm等)

总结

在深入理解Archaius过程中,有一个绕不开的“障碍”便是Apache Commons Configuration,由于前者强依赖于后者进行配置管理。正所谓你对Apache Commons Configuration有多了解,决定了你对Netflix Archaius的认识有多深。

作者:李浩宇/Alex
链接:https://www.cnblogs.com/liboware/p/15194221.html

上一篇下一篇

猜你喜欢

热点阅读