关于微服务:应用配置管理基础原理分析

58次阅读

共计 3329 个字符,预计需要花费 9 分钟才能阅读完成。

工程能够有点小乱,但配置不能含混;

一、配置架构

在微服务的代码工程中,配置管理是一项简单的事件,即须要做好各个环境的配置隔离措施,还须要确保生产环境的配置平安;如果划分的微服务足够的多,还要思考配置更新时的效率;

惯例状况下,在配置管理的体系中,分为四个次要的环境:开发、测试、灰度、生产;通常来说除了运维团队之外,其余人员没有查看灰度和生产配置的权限,以此来保障配置的安全性;配置核心的服务也会搭建两套:研发与生产各自独立部署。

二、配置形式

在我的项目中波及到的配置十分多,类型也很多,然而从大的构造上能够分为:工程级、利用级、组件级三大块;实际上这里只是单纯的从代码工程来看配置,如果把继续集成、自动化相干模块也思考进来的话,配置的治理会更加简单;

站在开发的角度来看,次要还是对利用级的配置进行治理,而在微服务的架构下,多个不同的服务既有大量雷同的配置,又存在各种差异化的自定义参数,所以在保护上有肯定的复杂性;

在单服务的工程中,利用中只会存在一个 bootstrap.yml 配置文件,配置内容根本就是服务名称,和配置核心地址等惯例内容,其余简单的配置都被关闭保护,防止核心内容泄露引发平安问题;

配置主体通常会被拆分成如下几个档次:环境管制,用来辨认灰度和生产;利用根底,治理和加载各个服务的通用配置;服务差别则配置在各自独立的文件内;并且对多个配置进行分类分层治理;以此保障配置的平安和升高保护难度。

三、Nacos 配置

首先还是从 bootstrap.yml 文件作为切入点,以当下常见的 Nacos 组件为例,围绕根底原理作为思路,来剖析服务工程是如何加载 Nacos 配置核心的参数;

spring:
  profiles:
    active: dev,facade
  cloud:
    nacos:
      config:
        prefix: application
        server-addr: 127.0.0.1:8848
        file-extension: yml

组件配置:配置逻辑中,单个服务端提供本身配置参数的信息,从上篇服务治理的源码中发现,这是一种很罕用的伎俩;须要基于这些信息去 Nacos 服务中加载配置;

@ConfigurationProperties("spring.cloud.nacos.config")
public class NacosConfigProperties {public Properties assembleConfigServiceProperties() {Properties properties = new Properties();
        properties.put("serverAddr", Objects.toString(this.serverAddr, ""));
        properties.put("namespace", Objects.toString(this.namespace, ""));
        return properties ;
    }
}

加载逻辑:服务启动时,先基于相应参数读取 Nacos 中配置的,而后解析数据并被 Spring 框架进行加载,加载的过程通过 MapPropertySource 类进行 Key 和 Value 的读取;

public class NacosPropertySourceBuilder {private List<PropertySource<?>> loadNacosData(String dataId, String group, String fileExtension) {
        // 查问配置
        String data = this.configService.getConfig(dataId, group, this.timeout);
        // 解析配置
        return NacosDataParserHandler.getInstance().parseNacosData(dataId, data, fileExtension);
    }
}

申请服务:服务端与 Nacos 核心通过 Http 申请的形式进行交互,通过 Get 申请携带参数,调用 Nacos 核心服务,从而获取相应配置;

public class ClientWorker implements Closeable {public String[] getServerConfig(String dataId, String group, String tenant, long readTimeout) {
        // 外围参数
        Map<String, String> params = new HashMap<String, String>(3);
        params.put("dataId", dataId);
        params.put("group", group);
        params.put("tenant", tenant);
        // 执行申请
        HttpRestResult<String> result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
    }
}

四、Spring 加载

从源码的结构图来看,配置文件的加载逻辑也是采纳事件模型实现的,这在后面工作治理中有具体的形容;配置的核心作用就是在程序启动时进行加载疏导,这里要害要了解 EnvironmentPostProcessor 的接口设计;

public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
    // 根底配置
    private static final String DEFAULT_NAMES = "application";
    public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
    public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
    static {Set<String> filteredProperties = new HashSet<>();
        filteredProperties.add("spring.profiles.active");
        filteredProperties.add("spring.profiles.include");
        LOAD_FILTERED_PROPERTY = Collections.unmodifiableSet(filteredProperties);
    }
    // 加载逻辑
    void load() {
    FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
            (defaultProperties) -> {});
    }
}

EnvironmentPostProcessor 接口:加载利用的自定义环境;

@FunctionalInterface
public interface EnvironmentPostProcessor {void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
}

SpringApplication:用于启动和疏导应用程序,提供创立程序上下文实例,初始化监听器,容器刷新等外围逻辑,能够围绕 run() 办法进行调试剖析;

ConfigurableEnvironment:环境配置的外围接口,波及到以后配置文件辨认,即 profiles.active;以及配置文件的解析能力,即PropertyResolver;在Loader 外部类中提供了构造方法和加载逻辑的实现。

五、参考源码

利用仓库:https://gitee.com/cicadasmile/butte-flyer-parent

组件封装:https://gitee.com/cicadasmile/butte-frame-parent

正文完
 0