分布式配置中心之思考
一、为什么需要分布式配置中心?它能解决什么问题?
从解决问题层面进行切入,它能解决配置混乱难管理的问题。
过去传统式开发,一个SSM框架开发的单体应用通常会有如下配置:
- spring-mybatis.xml;
- spring-mvc.xml;
- mybatis.xml;
- web.xml;
- jdbc.properties;
- log4j.properties;
- spring-redis.xml;
- spring-mongodb.xml;
- mapper目录下有若干xml。
当这个单体应用因为某种原因(新来的架构师按照微服务的方式进行重构以及拆分(逐步开展)、项目经理为了新的需求-新建项目(一般老项目不能轻易动,保险起见)等),这个时候就涉及到一个问题,新的项目目录结构与原来的可能一致,但配置文件基本上相同,这时将老项目的配置文件复制到新的项目,除非新的项目采取新的技术,否则仍然按照之前老项目的规范来,这个场景相信不少的朋友都遇到过。假如是两三个项目还好,如果这时要拆分为七八个甚至二十个,那么这样的工作将非常繁琐,同时维护上会很困难(稍不留神漏掉一个,最后一上线发现数据不对,原来连的还是开发环境的数据库,这时只得重新部署)。由此看来,分布式配置中心的主要作用在于对配置文件的统一管理,减少重复性工作,提高整体研发团队的效率(开发、测试、运维等)。
除此外统一管理体现的好处有安全性(可采用某种加密的方式进行关键配置数据加密,同时过去配置在代码里,如果代码被人反编译破解就可能导致密码之类的东西被泄漏等)、时效性(从两个方面来说,第一个方面是修改后重启才能生效,第二个是当时修改即刻生效)。
归纳地概括,因为多个项目场景中面临配置文件过于分散、修改追根溯源困难、环境容易搞混、代码与配置文件耦合等问题,我们需要分布式配置中心,而分布式配置中心恰好就能解决这样的问题。
二、分布式配置中心在实际中会面临哪些问题?
以Nacos为例,目前我使用Nacos作为分布式服务注册中心,而Nacos恰好集成了分布式配置管理。Nacos中的配置管理,就是管理配置文件的,而这些配置文件内容存储在MySQL。如果MySQL遭遇一些意外如磁盘空间满了、黑客攻击、连接过多、低效率的SQL导致内存消耗极大等,那么Nacos也会处于挂掉或死机状态(停止服务)等,这样也会直接导致一些微服务处理故障,虽然不在一个服务器上或者是连接的业务数据库不一样,但共同点都是读取Nacos统一管理下的配置。针对这样的问题一般从三个方面入手:
- 第一个方面,运维从监控策略(提前预警,做好应对)、服务器安全策略(防止攻击)、服务可用性策略(包含集群)等;
- 第二个方面,开发从写代码入手,遵守规范(代码规范),逻辑严谨(程序逻辑考虑较为全面),合理调用API(明白每个API的优缺点,进行合理组装,避免性能瓶颈)等;
- 第三个方面,测试从性能测试入手,模拟多人使用或非法攻击的场景等。
上面列举的仅仅是配置中心在实际落中面临的重大问题之一,除此之外还有就是如何规范管理配置(因为并不是所有的配置都需要放到配置中心进行统一管理,如果所有的微服务配置均放到分布式配置中心来管理,那么也会面临一个大问题就是如何管理好这些配置,一旦管理不好,就可能变成了体力劳动,违背了分布式配置中心的初衷)。
在提到规范管理之前,回到一个问题上,这个问题是究竟什么样的配置文件应该放在分布式配置中心?
我的回答是通用性配置,以我博客为例,application-dev.yml配置内容(我将jwt和鉴权、ribbon、hystrix等通用性配置放入了Nacos的配置管理):
# JWT配置 jwt: # 密匙KEY secret: JWTSecret # HeaderKEY tokenHeader: Authorization # Token前缀字符 tokenPrefix: challenger- # 过期时间 单位秒 1天后过期=86400 7天后过期=604800 expiration: 86400 # 配置不需要认证的接口 antMatchers: /login/**,/user/register,/api-doc/**,/login/**,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs/**,/druid/**,/cnblogs/**,/user/** # 有效时间 validTime: 7 ribbon: okhttp: enabled: true # NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 默认为;轮询,这里改为随机 ConnectTimeout: 5000 # 连接超时时间(ms) ReadTimeout: 5000 # 通信超时时间(ms) hystrix: enabled: true command: default: execution: isolation: thread: timeoutInMilliseconds: 6000 #
那么在规范性方面该如何落地?这与公司的实际情况有关,每家公司的业务、研发团队的综合素质等均存在差异性,而在规范性上就需要找到适合该公司研发团队的。但适合很难,都是从坑坑洼洼中摸索出来的。
以我个人经验来看(结合近来的坑),从以下入手:
- 通用性配置管理,公共通用性配置文件和业务通用性配置文件,放入分布式配置中心进行管理;
- 分类配置管理,不同环境(dev、test、prod)放入不同的分布式配置中心进行管理;
- 差异性配置管理,差异性配置文件放入具体的微服务项目,衡量差异性的标准是该配置只在此处用到,其它微服务均不涉及。
三、分布式配置中心的技术选型
关于这一方面,我特别查阅了相关资料,有博友将分布式配置中心的技术选型归纳为如下:
- Disconf;
- Spring Cloud Config;
- Apollo;
- Nacos。
目前用的比较多的,一个是SpringCloud Config,相当于是SpringCloud原生自带,不过该分布式配置中心的存储主要为SVN和Git,也有部分人采用本地存储的方式(存储在某个服务器上),另一个是Apollo,然后就是Nacos,至于Disconf早就不维护了,相当于落伍,GitHub如图:
对于早就不维护的,一般技术选型不考虑,关于技术选型需要考虑哪些东西,感兴趣的朋友可以阅读我的这篇文章:
从单体架构到分布式微服务架构的思考
四、SpringCloud Alibaba之分布式配置中心整合(以Nacos作为分布式配置中心)
1.添加Maven依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- SpringCloud Ailibaba Nacos Config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
2.bootstrap.yml配置
cloud: nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 配置文件格式 file-extension: yml # 共享配置 shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
3.例子
(1)通过nacos新建一个配置文件
(2)bootstrap.yml配置
cloud: nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 配置文件格式 file-extension: yml # 共享配置 shared-dataids: blog.properties,application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
(3)代码读取
a.Environment读取
@Autowired private Environment env env.getProperty("api_url")
b.注解读取
@Value("${api_url}") private String apiUrl;
(4)如果想实时更新的话需要配置两个地方(两者缺一不可,nacos版本为1.3.1)
a.配置文件
cloud: nacos: discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 配置文件格式 file-extension: yml # 共享配置 shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension},blog.properties refresh-enabled: true refreshable-dataids: blog.properties
b.注解
@RefreshScope