13-Dubbo的三大中心之配置中心

对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护。微服务的配置管理一般有以下需求:

  • *集中配置管理,一个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的。*
  • *不同环境不同配置,比如数据源配置在不同环境(开发,生产,测试)中是不同的。*
  • *运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小等。*
  • *配置修改后可自动更新。如配置内容发生变化,微服务可以自动更新配置。*

综上所述对于微服务架构而言,一套统一的,通用的管理配置机制是不可缺少的主要组成部分。常见的做法就是通过配置服务器进行管理。

不过对于来看这个文章的小伙伴应该大部分对配置中心都会比较了解,分布式配置中心实现简单一点就是借助Zookeeper来协助存储,变更推送,不过为了实现各种不同的业务需求,市面上已经有很多很可靠的配置中心可用了,比如我从其他地方拷贝过来的图(虽然不是最新的但是可以供大家参考下):

每个配置中心都有自己的实现,如果对配置中心感兴趣的小伙伴可以自行去对应开源项目官网查看,我们这里来看Dubbo对配置中心的支持

*多配置中心: Dubbo支持多配置中心,来 保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群 ,保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。-来自官网*

做中间件可能考虑更多的的不仅仅是性能,还要过多的考虑高可用,高可用怎么做呢,其实就是失效转移,主备切换,降级,降级再降级这些理论的运用,多多考虑某一个服务挂了怎么办,Dubbo的多配置中心支持增加了复杂性,不过降低了服务不可用的风险,有一定的人手的公司还是值得做的。

在上一个博客中说到了《12-全局视野来看Dubbo3.0.7的服务启动生命周期》Dubbo应用的启动过程DefaultApplicationDeployer的initialize()方法的全生命周期,在初始化方法中通过调用startConfigCenter();方法来启动配置中心的加载。后面就来详细看下:

DefaultApplicationDeployer类型的startConfigCenter()代码如下:

前面我们看到了配置管理器会从系统属性中加载配置这里我们来详细看下,配置往往是我们使用者比较关注的内容,

配置管理器加载配置代码:
来自ConfigManager的父类型AbstractConfigManager中

出于兼容性目的,如果没有明确指定配置中心,并且registryConfig的UseAConfigCenter为null或true,请使用registry作为默认配置中心
调用方法useRegistryAsConfigCenterIfNecessary()来处理逻辑
我们来看下代码:

  1. private void useRegistryAsConfigCenterIfNecessary() {
  2. // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
  3. //我们使用DynamicConfiguration的加载状态来决定是否已启动ConfigCenter。配置中心配置加载完成之后会初始化动态配置defaultDynamicConfiguration
  4. if (environment.getDynamicConfiguration().isPresent()) {
  5. return;
  6. }
  7. //从配置缓存中查询是否存在config-center相关配置 ,如果已经存在配置了就无需使用注册中心的配置地址直接返回
  8. if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {
  9. return;
  10. }
  11. // load registry
  12. //加载注册中心相关配置
  13. configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);
  14. //查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表
  15. List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
  16. //存在注册中心
  17. if (defaultRegistries.size() > 0) {
  18. defaultRegistries
  19. .stream()
  20. .filter(this::isUsedRegistryAsConfigCenter)
  21. //将注册中心配置映射转换为配置中心
  22. .map(this::registryAsConfigCenter)
  23. //遍历配置中心流
  24. .forEach(configCenter -> {
  25. if (configManager.getConfigCenter(configCenter.getId()).isPresent()) {
  26. return;
  27. }
  28. //配置管理器中添加配置中心,方便后去读取配置中心的配置信息
  29. configManager.addConfigCenter(configCenter);
  30. });
  31. }
  32. }

13.2.2.1 如何判断当前注册中心是否可以为配置中心

isUsedRegistryAsConfigCenter

这个扩展是否支持的逻辑判断是这样的扫描扩展类 看一下当前扩展类型是否有对应协议的扩展 比如在扩展文件里面这样配置过后是支持的 protocol=xxxImpl
配置中心的动态配置的扩展类型为 org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory

  1. zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory

13.2.2.2 注册中心配置转配置中心配置

这个逻辑是registryAsConfigCenter方法,我来贴一下代码:

来自AbstractConfig类型的refresh()方法

  1. public void refresh() {
  2. refreshed.set(true);
  3. try {
  4. // check and init before do refresh
  5. //刷新之前执行的逻辑 这里并做什么逻辑
  6. preProcessRefresh();
  7. //获取当前域模型的环境信息对象
  8. Environment environment = getScopeModel().getModelEnvironment();
  9. List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();
  10. // Search props starts with PREFIX in order
  11. String preferredPrefix = null;
  12. for (String prefix : getPrefixes()) {
  13. if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) {
  14. preferredPrefix = prefix;
  15. break;
  16. }
  17. if (preferredPrefix == null) {
  18. preferredPrefix = getPrefixes().get(0);
  19. }
  20. // Extract sub props (which key was starts with preferredPrefix)
  21. Collection<Map<String, String>> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix);
  22. Map<String, String> subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix);
  23. InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties);
  24. String idOrName = "";
  25. if (StringUtils.hasText(this.getId())) {
  26. idOrName = "[id=" + this.getId() + "]";
  27. } else {
  28. String name = ReflectUtils.getProperty(this, "getName");
  29. if (StringUtils.hasText(name)) {
  30. idOrName = "[name=" + name + "]";
  31. }
  32. }
  33. logger.debug("Refreshing " + this.getClass().getSimpleName() + idOrName +
  34. " with prefix [" + preferredPrefix +
  35. "], extracted props: " + subProperties);
  36. }
  37. assignProperties(this, environment, subProperties, subPropsConfiguration);
  38. // process extra refresh of subclass, e.g. refresh method configs
  39. processExtraRefresh(preferredPrefix, subPropsConfiguration);
  40. } catch (Exception e) {
  41. logger.error("Failed to override field value of config bean: " + this, e);
  42. throw new IllegalStateException("Failed to override field value of config bean: " + this, e);
  43. }
  44. postProcessRefresh();

在这里插入图片描述

ConfigCenterConfig类型
下面配置信息来自官网
dubbo:config-center 配置

配置中心。对应的配置类:org.apache.dubbo.config.ConfigCenterConfig

技术咨询支持,可以扫描微信公众号进行回复咨询
在这里插入图片描述