微服务开发系列:开篇
微服务开发系列:为什么选择 kotlin
微服务开发系列:为什么用 gradle 构建
微服务开发系列:目录结构,保持整洁的文件环境
微服务开发系列:服务发现,nacos 的小补充
微服务开发系列:怎样在框架中选择开源工具
微服务开发系列:数据库 orm 使用
微服务开发系列:如何打印好日志
微服务开发系列:鉴权
微服务开发系列:认识到序列化的重要性
微服务开发系列:设计一个统一的 http 接口内容形式
微服务开发系列:利用异常特性,把异常纳入框架管理之中
微服务开发系列:利用 knife4j,生成最适合微服务的文档
1 目录统一
系统中有一个统一的目录结构绝对是必要的,我见过很多项目对目录结构完全没有定义,每个开发人员都按自己的喜好规则随意的定义目录在哪里。
这样会产生很多的问题,对于系统日后的维护,环境中问题的排查都会产生阻碍。
因此目录的环境一定要有规律,这样不论是排查问题,还是为了以后的维护,都是有益的。
我遇见过的目录统一的类型分为五种
- 系统依赖服务的安装路径,例如 mysql、redis等,如果是自己来安装,需要提前规划好目录位置
- 系统依赖服务产生或者依赖的文件
- 系统自身服务的安装路径
- 系统自身服务产生或者依赖的文件
- 系统集成的 jar 产生或者依赖的文件
2 以 nacos 和 arthas 为例解决产生的文件位置冲突问题
如果面临的环境复杂多变,不建议过于依赖 arthas,目前框架中已经移除。
nacos 和 arthas 两个产生文件的典型依赖模块,就是上述说的第五点。
nacos 会在主目录生成两个文件夹
$HOME/nacos
,配置文件地址$HOME/logs
,日志文件地址
arthas 会生成三个文件夹
- arthas 日志地址
- arthas-cache 日志地址
- 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 中。
该自动装载类生效的条件如下:
- 需要通过在
spring.factories
配置org.springframework.cloud.bootstrap.BootstrapConfiguration
,否则不能在 nacos 之前让变量生效 - 需要添加
@AutoConfigureBefore(NacosConfigBootstrapConfiguration.class)
依然是为了保证在 nacos 读取到变量之前生效 - 需要添加
@AutoConfigureAfter(Environment.class)
需要保证 spring 的变量初始化完成后生效,否则不能获取到spring.application.name
的值
满足以上三点后,就能够动态的配置文件路径,不用在项目中添加额外的环境变量,如果有其它依赖也有类似的问题,相同的思路依然可使用。
除此之外,GlobalCommonVarConfig
还添加了两个配置 nacos 域的读取方式,使用的前提是每个模块下面的 bootstrap.yml
配置 spring.cloud.nacos.config.namespace
需要是固定值 ${nacosNamespace:vte-server}
,否则不会生效。
- 第一个是读取
${HOME}/.server.namespace
文件,配置这个是为了多项目在同一个用户下,在改变域的时候,不用为每个项目都单独配置域 - 第二个是直接设置
nacosNamespace
的变量值,如果一个用户下需要同时启动两个相同的模块,但是需要访问不同的域,就可以使用该方法
如果都不设置,就会使用配置文件中变量配置的默认值。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。