愿君学长松,慎勿作桃李。这篇文章主要讲述微服务技术专题Netflix动态化配置服务-微服务配置组件变色龙Archaius相关的知识,希望能为你提供帮助。
前提介绍
- 如果要设计开发一套微服务基础架构,参数化配置是一个非常重要的点,而Netflix也开源了一个叫变色龙Archaius的配置中心客户端,而且Archaius可以说是比其他客户端具备更多生产级特性,也更灵活。
- 在NetflixOSS微服务技术栈中,几乎所有的其它组件(例如Zuul, Hystrix, Eureka, Ribbon等)都依赖于Archaius,可以说理解Archaius是理解和使用Netflix其它微服务组件的基础。
文章图片
Netflix Archaius是一个配置管理库,其重点是来自多个配置存储的动态属性。它包括一组用于Netflix的Java配置管理API。它主要实现为Apache Commons Configuration库的扩展。提供的主要功能有:
Archaius项目的由来
- 在微服务环境下,配置常常需要根据不同的上下文环境进行调整,或者说配置应该是多维度的。例如在Netflix,上下文维度包括环境(开发、测试和生产)。
- Netflix希望能够根据发布的环境,甚至请求的上下文,动态地调整服务的配置,让Netflix的整个系统的行为和逻辑变得动态可调配,以适应互联网应用快速多变的需求。为此,Netflix平台团队开发了配置中心产品,团队将这个产品形象地称为变色龙Archaius,因为变色龙这种动物能够根据自己所处的环境动态调整身体的颜色。
- 根据请求上下文开启或关闭某项功能。
- 某个页面缺省显示10个商品,在某些情况下,可以通过Archaius调整配置,只显示5个商品。
- 动态调整Hystrix熔断器的行为。
- 调整服务调用客户端的连接和请求超时参数。
- 如果某个线上服务产生出错告警,可以动态调整日志输出级别(粒度可以细到包或者组件级别),这样可以通过详细日志排查问题。问题定位以后,再将日志输出级别恢复到默认级别。
- 对于多区域或者多国家部署的应用,通过动态配置,可以根据不同区域和国家开启不同的功能。
- 可以根据用户的实际访问模式动态调整一些基础中间件的配置,例如缓存的存活时间TTL(Time To Live)。
- 数据库访问客户端的连接池配置,可以对不同服务配不同的值。例如,一个请求频率RPS(Request Per Second)小的服务,可以配置较小的连接数,而一个请求频率大的服务,可以配置较大的连接数。
- 运行期配置的变更可以在不同维度生效,例如集群中的单个实例维度,多区域部署下的某个区域维度,某个服务栈维度,或者某个应用集群维度。
- 功能开关(Feature Flag)发布,有些功能虽然上线,但是并不马上启用,而是通过配置开关动态启用,这样可以根据情况灵活开启或者关闭某项线上功能。
- 金丝雀发布(Canary Release),新功能上线时,让新老集群同时并存一段时间,通过配置将到老集群的流量逐步动态调整到新集群,如果监控显示无异常,则完成新集群的上线,如异常,则快速切回老集群。
- archaius是netflix开源的动态属性配置框架,基于apache commons configuration, 提供在运行时获取配置值的功能。
- Archaius的核心是可以容纳一个或多个配置的复合配置的概念。每个配置都可以从诸如JDBC、REST接口、xxx.properties文件等配置源中获取。可以选择在运行时对配置源进行轮询以进行动态更改,
- 属性的最终值取决于包含该属性的最顶层配置(因为是复合配置)。即,如果一个属性存在于多个配置中,则应用程序看到的实际值将是配置层次结构中最顶层插槽中的值,当然这种层次结构是可以配置的。
- 配置可动态调整:动态、类型属性
- 配置支持类型(Int, Long, Boolean等)。
- 高性能和线程安全:高吞吐量和线程安全的配置操作
- 提供一个拉(pulling)配置的框架,可以从配置源动态拉取变更的配置。(一个轮询框架,允许用户获取对配置源的属性更改)
- 支持回调(callback)机制,在配置变更时自动调用。
- 支持JMX MBean,可以通过JConsole查看配置和修改配置。
文章图片
Achaius的核心是一个称为组合配置(Composite Configuration)的概念,简单可以理解为一个分层级的配置,层级有优先级,高优先级的层级的配置会覆盖低优先级的配置。每一个层级可以从某个配置源获取配置,例如本地配置文件,JDBC数据源,远程REST API等。配置源还可以在运行时动态拉取变更,例如在上图中,持久化数据库配置(Persisted DB Configuration)是指将配置存在关系数据库中,相应的配置源会定期从数据库拉取变更)。配置的最终值由顶级配置决定,例如,如果多个层级都含有某个配置项,那么应用最终见到的值是配置层级中最顶层的值。配置分层的顺序是可以调整的。
通过archaius获取配置值,有两种方式:
- 一种是通过ConfigurationManager获取到配置中心实例,然后通过propName获取配置值,通过ConfigurationManager获取配置
文章图片
- 另外一种方式是通过DynamicPropertyFactory,获取配置项的DynamicProperty wrapper。
文章图片
Archaius是什么?
- ConcurrentMapConfiguration提供将配置项配置值放在ConcurrentHashMap中维护的功能。
文章图片
- DynamicConfiguration提供动态从数据源获取所有配置值的功能,通过轮询数据源更新配置值。
文章图片
- DynamicWatchedConfiguration也是提供动态更新配置的功能,与DynamicConfiguration不同的是,配置更新是数据源有变化时触发的。
- DynamicConfiguration是pull方式,DynamicWatchedConfiguration是push方式。
文章图片
- DynamicPropertyFactory持有AbstractConfiguration实例。
- 创建DynamicProperty对象时,DynamicProperty对象会获取DynamicPropertyFactory持有的AbstractConfiguration实例。
- DynamicProperty对象会向AbstractConfiguration实例注册DynamicPropertyListener, 当AbstractConfiguration有增删改查变化时,会通知到当前的DynamicProperty对象。
文章图片
AbstractConfiguration是怎么注入的?有以下几种方式注入AbstractConfiguration。
- 配置archaius.default.configuration.class 指定AbstractConfiguration实现类
- 配置 archaius.default.configuration.factory 指定AbstractConfiguration实例工厂方法类,工厂方法类需要实现getInstance方法返回AbstractConfiguration实例
- 【微服务技术专题Netflix动态化配置服务-微服务配置组件变色龙Archaius】调用 ConfigurationManager 的 install(AbstractConfiguration config)方法
- 调用DynamicPropertyFactory 的 initWithConfigurationSource(AbstractConfiguration config) 方法
<
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);
}
总结资料参考
- https://github.com/netflix/archaius
- http://techblog.ppdai.com/2018/05/08/20180508/
推荐阅读
- 接口数据使用了 RSA 加密和签名(一篇文章带你搞定)
- zabbix监控mysql_slave状态
- 嵌入式C语言的高级使用(全网最详细)
- 如何执行许多ajax请求并使用jQuery $ .ajax仅在1个回调中获得结果
- 如何在Laravel中检索信息和任何加密货币(比特币,以太坊)的值
- 如何使用OCRA在Windows中从Ruby脚本创建可执行文件(.exe)
- 如何使用Artyom.js在ReactJS中创建自己的语音助手
- 使用CSS删除内联块元素之间的空白(Gap)
- 如何使用jQuery将YouTube视频用作页面背景