微服务开发系列:目录结构,保持整洁的文件环境

源码地址

1 目录统一

系统中有一个统一的目录结构绝对是必要的,我见过很多项目对目录结构完全没有定义,每个开发人员都按自己的喜好规则随意的定义目录在哪里。

这样会产生很多的问题,对于系统日后的维护,环境中问题的排查都会产生阻碍。

因此目录的环境一定要有规律,这样不论是排查问题,还是为了以后的维护,都是有益的。

我遇见过的目录统一的类型分为五种

  1. 系统依赖服务的安装路径,例如 mysql、redis等,如果是自己来安装,需要提前规划好目录位置
  2. 系统依赖服务产生或者依赖的文件
  3. 系统自身服务的安装路径
  4. 系统自身服务产生或者依赖的文件
  5. 系统集成的 jar 产生或者依赖的文件

2 以 nacos 和 arthas 为例解决产生的文件位置冲突问题

如果面临的环境复杂多变,不建议过于依赖 arthas,目前框架中已经移除。

nacos 和 arthas 两个产生文件的典型依赖模块,就是上述说的第五点。

nacos 会在主目录生成两个文件夹

  1. $HOME/nacos,配置文件地址
  2. $HOME/logs,日志文件地址

arthas 会生成三个文件夹

  1. arthas 日志地址
  2. arthas-cache 日志地址
  3. arthas-output 地址

对于 nacos 和 arthas 这两个服务,对这几个位置都提供了环境变量设置,有些在文档里,有些并不在,只能自己翻源码去找,甚至还有些变量文档里面有,但是已经不能用了,还是要到源码里面找。

这些目录中,非日志的目录配置使用环境变量我能理解,但是对于日志为什么也需要配置我就不明白了,我见过的所有模块都是只打印日志,但是不对日志进行配置,交由用户自己去配置日志。

nacos 和 arthas 都有自己的 logback.xml 日志配置文件,令人费解。

对此我提交了 issues 给 nacos(最后已经做出了解释,但是并没有提供解决下面问题的方案)。

最大的问题是,文件冲突

当一个用户下面,部署多个自身系统的服务并且都使用了 nacos 或者 arthas 时,多个文件就会输出在一个位置,完全无法确定是哪个服务正在打印,虽然你可能不会去看这个文件,但是不代表不用去解决它。

一开始想到过使用 spring.application.name 的变量区分目录位置,但是这两个依赖使用变量时用的是 System,而 spring.application.name 只在 spring 设置的阶段后生效,然而 nacos 在该变量未设置之前就获取了,所以获取该值只能是 spring.application.name_IS_UNDEFINED

我想到的第一个解决方法是利用 PID 环境变量:

-DSERVER_COMMON.BASE=${HOME}/server-common
-DARTHAS_LOG_PATH=${SERVER_COMMON.BASE:-${HOME}/server-common}/logs/arthas/${PID}
-DRESULT_LOG_FILE=${SERVER_COMMON.BASE:-${HOME}/server-common}/logs/arthas-cache/${PID}/result.log
-DJM.LOG.PATH=${SERVER_COMMON.BASE:-${HOME}/server-common}/logs/nacos/${PID}
# 注意到这里没有使用上面的值相同的变量 ${SERVER_COMMON.BASE},因此它不支持~,翻看过源码,获取环境变量的方式不对
-DJM.SNAPSHOT.PATH=${HOME}/server-common
-Darthas.outputPath=${SERVER_COMMON.BASE:-${HOME}/server-common}/arthas-output/${PID}

这样的方法虽然能解决,但是经常重启,PID 改变频繁,不是长久之计。

在经过一段时间的探索之后,我在框架中提供了一个自动装载类 framework:cn.framework.config.GlobalCommonVarConfig,动态的设置这几个变量的值,这个类的代码也开放在了上面的 issue 中。

该自动装载类生效的条件如下:

  1. 需要通过在 spring.factories 配置 org.springframework.cloud.bootstrap.BootstrapConfiguration,否则不能在 nacos 之前让变量生效
  2. 需要添加 @AutoConfigureBefore(NacosConfigBootstrapConfiguration.class) 依然是为了保证在 nacos 读取到变量之前生效
  3. 需要添加 @AutoConfigureAfter(Environment.class) 需要保证 spring 的变量初始化完成后生效,否则不能获取到 spring.application.name 的值

满足以上三点后,就能够动态的配置文件路径,不用在项目中添加额外的环境变量,如果有其它依赖也有类似的问题,相同的思路依然可使用。

除此之外,GlobalCommonVarConfig 还添加了两个配置 nacos 域的读取方式,使用的前提是每个模块下面的 bootstrap.yml 配置 spring.cloud.nacos.config.namespace 需要是固定值 ${nacosNamespace:vte-server},否则不会生效。

  1. 第一个是读取 ${HOME}/.server.namespace 文件,配置这个是为了多项目在同一个用户下,在改变域的时候,不用为每个项目都单独配置域
  2. 第二个是直接设置 nacosNamespace 的变量值,如果一个用户下需要同时启动两个相同的模块,但是需要访问不同的域,就可以使用该方法

如果都不设置,就会使用配置文件中变量配置的默认值。

本文参与了思否技术征文,欢迎正在阅读的你也加入。

你可能感兴趣的:(微服务后端思否技术征文目录)