先说一个我印象特别深刻的生产事故。去年我们做微服务改造,把原本一个单体应用拆成了二十多个服务,配置管理却还停留在一台服务器一套配置的老路上——数据库连接串、Redis 地址、MQ Topic 到处都是,谁想改就改,谁也不确定还有多少份拷贝散落在各个环境。那回联调,A 服务连的是测试库,B 服务连的是预发库,两边数据对不上,一群人查了大半天,最后发现是某个同事改公共配置的时候只同步了部分服务,剩下几个还指向老地址。就是从那天起,我下定决心把配置统一收口。
正好那段时间公司推进中间件国产化,应用服务器换成了宝兰德应用服务器微服务版本 V11.5.0,这个版本原生支持接入 ZooKeeper 配置中心。借着这个契机,我把整套微服务的配置都迁到了 ZooKeeper 上。这篇文章就把整个接入过程、原理和这半年踩过的坑从头到尾梳理一遍,给正在做同类改造的同学一个可参考的路径。
1. 为什么非要把配置从服务里“赶”出来
1.1 微服务拆完之后,配置管理会变成灾难
单体应用时代,配置一般集中在一个 application.properties 或者一个配置目录里,改完重新发布一次就行,哪怕目录多,也还是在一个代码仓库里。微服务化之后情况就完全不一样了:服务数量翻了好几倍,每个服务又有开发、测试、预发、生产四套环境,配置项互相交叉,又互相独立。我最直观的感受就是,光维护“哪个服务连哪个库”这么一张表,团队里就得有一个人专门盯着,否则一不留神就串了环境。
改配置本身也是个麻烦事。传统方式下,配置是随应用包一起打包发布的,想改一个参数就得重新构建、重新发布,整个过程至少要十几分钟。遇到线上问题需要调日志级别、改超时时间,这种“重启才能生效”的模式在生产上是非常痛苦的。更不要说多个服务依赖同一份配置的时候,比如上游接口的地址变了,你得挨个服务去改、去发布,漏掉任何一个,故障就来了。
所以微服务架构做到一定规模,配置中心就不是“可选项”,而是“必选项”。配置集中管理以后,一份配置一处修改,所有订阅的服务自动感知并生效,这才是分布式系统该有的配置管理形态。
1.2 ZooKeeper 能当配置中心的底层逻辑
很多人一听到 ZooKeeper,第一反应是“分布式协调服务”,是给 Kafka、Dubbo 做注册中心用的,用它做配置中心总觉得有点跨界。其实 ZooKeeper 的设计天然适合做配置管理,核心就在于它的数据模型和监听机制。
ZooKeeper 的数据存储结构是一个树形命名空间,类似文件系统目录树,每个节点叫 znode。znode 可以存数据,也可以有子节点,路径本身就带有业务含义。比如 /bes/config/order-service/prod/datasource 这个节点,一眼就能看出来是 order-service 服务在 prod 环境下的数据源配置。我经常跟团队里的人打比方:你把 ZooKeeper 当成一个“分布式文件系统”来理解就顺了,只是这个文件系统多了一个特别重要的能力——每个节点都能挂监听器。
这个能力就是 Watcher 机制。客户端可以监听某个节点或者节点的子节点,一旦节点数据发生变化,ZooKeeper 服务端会主动推送通知给客户端。用到配置管理上就是:客户端启动时读取配置并注册监听,服务端配置变更后推送通知,客户端收到通知再重新拉取配置,整个过程完全自动化,不需要人工干预。这就是动态刷新能够实现的底层原因。
1.3 为什么选了 ZooKeeper 而不是 Nacos 或 Consul
这个话题在团队里也争论过。Nacos 在国内很火,配置管理、服务发现二合一,控制台用起来也方便;Consul 在云原生场景下也有不少拥趸。最终我们还是选了 ZooKeeper,有几个很实际的考虑。
第一,宝兰德微服务版本本身对 ZooKeeper 的适配是开箱即用的,接入成本最低。第二,我们这套微服务框架里 ZooKeeper 本来就承担了注册中心和分布式锁的职责,再让它管配置,等于一套集群干三件事,运维上不用额外维护一套配置中心系统。第三,团队对 ZooKeeper 的运维经验相对丰富,出了故障能快速定位。
Nacos 当然有它的优势,比如自带控制台、可视化配置管理,但对我们的规模来说,ZooKeeper + 自建的管理脚本已经完全够用了。选型这件事没有绝对的对错,关键是匹配团队现状和业务规模。如果你没有任何 ZooKeeper 基础,纯粹是为了配置管理,那 Nacos 可能上手更快;但如果你已经有一套 ZooKeeper 集群,而且微服务框架本身也依赖它,那复用起来是最省事的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 宝兰德微服务版的配置架构:ZooKeeper 到底插在哪一层
2.1 V11.5.0 的运行形态和配置来源
宝兰德应用服务器微服务版本 V11.5.0 不是一个纯粹的 Spring Cloud 套件,它是把应用服务器从单体形态往微服务形态延伸的产品——既有传统应用服务器的管理能力,比如部署、监控、日志、安全管理,又提供了微服务场景下的服务注册发现、配置管理、负载均衡这些能力。
在这个版本里,配置来源是有优先级的,它不是一上来就去 ZooKeeper 拉配置,而是有一个加载顺序。我梳理了一下,大致是这样一个链路:
- 启动时先加载应用服务器自身的基础配置,包括端口、JVM 参数、日志级别这些;
- 再加载应用级配置,也就是你打包在应用里的配置文件和本地配置;
- 如果配置了 ZooKeeper 地址,会再去 ZooKeeper 上拉取远端配置;
- 远端配置在粒度上覆盖本地配置,同名配置项以远端为准。
也就是说,ZooKeeper 在这里是“最高优先级的配置源”,但不是唯一的配置源。本地配置作为兜底保留,防止 ZooKeeper 集群出故障时应用完全起不来。这个设计我后来想想是非常合理的,配置中心挂了不能把业务也拖死,至少能用本地缓存的一份配置继续跑一段时间。
2.2 配置的三层拆分
我们在规划配置的时候,把配置拆成了三个层次,每一层对应不同的管理方式和变更频率。
第一层是平台配置,包括应用服务器的端口、内存参数、线程池大小、JVM 参数这些。这一层基本很少动,属于“基础设施级”配置,放不放 ZooKeeper 其实都行,但我们还是放上去了,为的是新节点扩容的时候不需要
