基于 Zookeeper 实现配置中心


3/29/2017 zookeeper

基于 Zookeeper 实现的一个配置中心

现在架构存在的问题

  1. 配置分散 比如修改日志配置需要修改 fkh-api, fkh-webgis, ..., fkh-server.
  2. 只有 dev, test, pro 本地开发时需要修改 dubbo.server.version, 提交时忘记改回来造成服务调用出错.
  3. 配置类太多, 且有重复的配置类, 不好管理
  4. 非开发环境下应用配置在 war 包中, 关键配置明文显示
  5. 修改配置后, 需要重新打包部署
  6. 关键配置随时可修改, 一不小心就会造成生产事故

为了统一管理配置. 现将配置从 pom 中迁入到 fkh-common-config, 使用 maven filter 实现根据不同环境从 ${env}.fkhwl.properties 获取配置替换 application.properties 配置(@占位符替换) 使用 <context:property-placeholder/> 配合 @Value("${}") 实现自动注入配置到配置类. 新增 local 环境用于本地开发

但是仍然解决不了敏感配置的安全, 配置不能统一管理等问题.

解决方案

使用配置中心, 统一管理配置, 将敏感配置隔离出来.

借助 ZooKeeper我们实现的配置信息存储方案具有的优点如下:

  1. 简单. 尽管前期搭建ZooKeeper服务器集群较为麻烦,但是实现该方案后,修改配置整个过程变得简单很多. 用户只要修改配置,无需进行其他任何操作,配置自动生效.
  2. 可靠. ZooKeeper服务集群具有无单点失效的特性,使整个系统更加可靠. 即使ZooKeeper 集群中的一台机器失效,也不会影响整体服务,更不会影响分布式应用配置信息的更新.
  3. 实时. ZooKeeper的数据更新通知机制,可以在数据发生变化后,立即通知给分布式应用程序,具有很强的变化响应能力.

能解决的问题

  • 保证不同部署环境下应用配置的隔离性
  • 保证非开发环境下应用配置的保密性
  • 保证不同部署节点上同一应用配置的一致性
  • 实现分布式环境下应用配置的可管理性

配置分类

现有配置

# 环境变量
env
# api 测试使用
ignore.auth.flag
# 日志配置
#  JDBC
# 图片上传配置
# SSDB
# kafka配置信息
# activemq配置信息
# dubbo配置
# 兑吧
...
1
2
3
4
5
6
7
8
9
10
11
12
13

来源

  1. 本地配置文件
  2. 数据库
  3. Redis
  4. Zookeeper

读写频率

  1. 单次读取型
    1. dubbo.service.version
    2. Logback
  2. 多次读取型(本地开发时动态切换环境)
    1. MongoDB
    2. Kafka
    3. Zookeeper
    4. JDBC
    5. Redis
    6. SSDB
  3. 动态读取型
    1. 字典数据
    2. waybill.upload
    3. 保险
    4. 支付
    5. 企查查
    6. 声网
    7. 上传地址
    8. 定位、话费、礼品兑换开关配置
    9. 商务端推送配置
    10. 兑吧配置
    11. 个推
    12. 中交配置
    13. 容联云配置

总体设计

系统架构

5F39EFAE-DB2F-40C0-B049-AC3A91D2B662

基础模型

5788CAAC-DABA-4FD8-B744-7BD223BDEC05

  • 用户通过配置中心修改 zk 节点配置
  • client 监听到节点数据被修改, 获取 spring 容器配置类, 动态修改配置

序列图

Config center

功能:

  1. 统一管理配置
  2. 修改日志级别
  3. 修改日志采集率
  4. 查看应用状态(是否在线, 上次部署时间等)

后期考虑增加的功能

  1. 应用下线邮件(短信/微信)提示
  2. kafka 操作, 查看信息
  3. dubbo 服务注册信息

6C0DABE9-7360-4712-87A0-5FF088BE

Client

启动时读取配置, 运行时根据配置调整行为

2B1B0B88-EDDD-4D31-B3FF-D400E711D

Zookeeper 配置节点设计

DBDF288B-770D-46D5-AA92-160893C683A5

只有 local 环境才有人员节点

只有 local 是本地开发配置, 因为开发需要,有时会切换不同配置, 因此将配置分配到具体开发者身上, 这样修改一个配置时, 只会对某个开发者生效, 不影响其他人

节点不能共用

意思是不能抽取出公共的配置, 因为修改了公共配置, 监听此节点的 client 都会修改配置.

模块说明

Client 端

Client 端暂时放在 trace 模块中, 方便开发测试

配置中心 admin

.
├── common-parent                       # 所有模块的父模块, 负责版本与依赖控制
├── common-utils                        # 公共工具类
├── fkh-api-manager                     # 未来要做的 api 管理系统
│   └── api-manager-rest                # api 管理系统的 rest 接口
├── fkh-config-server                   # 配置中心父模块
│   ├── fkh-config-admin                # 配置中心前端
│   └── fkh-config-rest                 # 配置中心 rest 接口
└── spring-boot-starter-curator         # 封装的 curator spring boot start
1
2
3
4
5
6
7
8
9

技术选型

Curator(馆长, 管理员)

替代 Zkclient 的另一个简单强大的 Zookeeper 客户端, (Curator)馆长与(Zookeeper)动物园, 天生一对 🤣🤣

Curator包含了几个包:

  • curator-framework: 对zookeeper的底层api的一些封装
  • curator-client: 提供一些客户端的操作, 例如重试策略等
  • curator-recipes: 封装了一些高级特性, 如: Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等

Spring Boot

用于开发配置中心的 Web 端框架, 实现快速开发, 简单部署.

Fkh 开发配置管理解决方案

  1. clone 代码到本地(git 并没有管理 fkh-common-config 中的 application.yml)
  2. maven profile 选择 local(默认)
  3. 执行 fkh-common-config 的 pullConfig() 方法, 用于拉取配置
  4. 完成后会在 resource 目录下生成 application.yml 文件, 用于编译时替换占位符(这里是考虑使用 @Bean注入 jdbc, redis, kafka, mongodb 等对象, 但是 dubbo 和 logback 注入有问题, 以后会优化这里)
env: local
# zookeeper 配置
zookeeper:
        connect:
            list: 192.168.2.8:2181
# dubbo 配置
dubbo:
        service:
            version: 5.2.8
...
1
2
3
4
5
6
7
8
9
10

其他配置这会根据 maven profile ,启动 app 时动态注入. 本地开发时, 以本地配置优先, 没有配置的则读取 zk 配置.

如果从 local 切换到 test 环境, 需要再次运行 pullConfig() , 只有以下配置不会被替换

# zookeeper 配置
zookeeper:
  connect:
    list: 192.168.2.8:2181
# dubbo 配置
dubbo:
  service:
    version: 5.2.8
# 日志配置
logback:
  log:
    level: DEBUG
    root:
      level: ERROR
  appender:
    one: STDOUT
    two:
  logstash:
    ip: 192.168.2.121:8801
  path: /Users/codeai/Develop/logs/fkh/mnt/syslogs/tomcat
# 上传配置
uploadPath: /data/devuploads/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

这样可以避免切换环境后还要手动修改配置

开发时切换配置

可能有这样的需求, 我们开始在 local 环境开发, test 环境有出现 bug, 为了复现 bug, 我们可能会切换到 test 环境.

这个的解决方案:

我们不需要重启应用, 直接在 Web 端切换这个开发者的配置即可.

原理:

切换功能只会将 test 的配置替换到当前开发者节点下的 local 配置, 然后自动调用 zk 监听机制, 动态修改配置即可.

Dev Test Prod 环境部署解决方案

当需要部署到非 local 环境的服务器时, 需要执行 fkh-common-config 中的 pullDeployConfig() 方法

pullConfig()pullDeployConfig() 的区别:

因开发需要切换环境时, 调用 pullConfig() 后不会覆盖 application.yml 中自定义配置.

因为部署时, 并不需要本地自定义配置, 因此 pullDeployConfig() 会将原来的 application.yml 重命名为 application.yml.local(不会被打包到 war 中), 然后拉取配置生成 application.yml

第三方公司配置解决方案

第三方公司配置由返空汇统一管理, 只需要在 configs 节点下增加一个子节点, 比如 chengtong, 然后再添加配置节点

打包时, 切换到 chengtong 分支, maven 选择 chengtong profile, 如果需要个性化配置, 在本地新建 application.yml 配置即可, 默认会以本地优先(只针对第三方公司)

如果是 fkh 公司, 以 dev,test,prod 环境打包时, 则会忽略本地配置文件.

原因是开发时拉取配置,个性化配置后(修改 dubbo service version, 修改日志输出等), 不小心提交了本地配置, 打包时不影响, 依然是以 zk 配置为主.

Todo list

  1. 迁移项目中的配置文件及类到 fkh-common-config
    1. 使用@Value("${...}") 替换 xml 的 bean 配置
  2. 整理 fkh-common-config 中的配置映射到zk的节点
  3. 实现一键创建zk节点
    1. shell 命令或者 Go 实现
  4. 从数据源(zk、mysql、redis)读取配置信息写入properties
    1. 实现 pullConfig() 方法 2. 合并本地配置, 切换环境时, 哪些配置不需要覆盖
    2. 实现 pullDeployConfig() 方法
      1. 文件重命名
      2. 重新生成 properties .yml
  5. mvn打包前, 读取配置替换 xml 中的占位符(dubbo、logstash)
    1. 删除多余环境配置,只保留 application.yml
    2. 修改 maven 的 profiles
    3. 修改 maven 的 build filter
  6. 从 Java 对象中映射到 Env 环境配置类中
    1. 启动时读取 zk(mysql, redis) 配置(不包括 jdbc, redis, logback..)
    2. 在实例化 bean 之前,将配置动态注入到 Spring Environment 对象中
    3. 启动完成后添加 listener, 监听配置变化
    4. 实现 callback, 动态修改配置
Last Updated: 7/3/2019, 6:17:56 PM