11.7.1 配置管理与动态刷新实践
配置管理是 ZooKeeper 典型场景之一,通过持久节点保存配置值,子节点承载环境/应用维度,Watcher 实现动态刷新。适合多环境配置分发、灰度开关、参数中心等场景。
原理草图(配置发布与动态刷新):
安装与启动示例(单机演示):
# 1) 下载并解压
tar -xf apache-zookeeper-3.8.4-bin.tar.gz -C /opt/
ln -s /opt/apache-zookeeper-3.8.4-bin /opt/zookeeper
# 2) 配置
cat >/opt/zookeeper/conf/zoo.cfg <<'EOF'
tickTime=2000
dataDir=/data/zookeeper
clientPort=2181
EOF
# 3) 启动
/opt/zookeeper/bin/zkServer.sh start
/opt/zookeeper/bin/zkServer.sh status
# 预期输出:Mode: standalone
目录规划与数据模型示例:
# 规划:/config/{env}/{app}/{module}
# 创建环境与应用目录
/opt/zookeeper/bin/zkCli.sh <<'EOF'
create /config ""
create /config/prod ""
create /config/prod/appA ""
create /config/prod/appA/db "jdbc:mysql://10.0.0.10:3306/appA"
create /config/prod/appA/feature "{\"switch\":\"on\",\"percent\":10}"
EOF
动态刷新实践流程(命令级演示):
# 终端1:注册 Watcher(一次性触发)
/opt/zookeeper/bin/zkCli.sh
get -w /config/prod/appA/db
# 终端2:更新配置触发 Watcher
/opt/zookeeper/bin/zkCli.sh
set /config/prod/appA/db "jdbc:mysql://10.0.0.11:3306/appA"
# 终端1预期:触发 WATCHER 事件并显示新值
# 注意:需在回调中重新注册 get -w 以持续监听
应用侧伪代码示例(体现 rewatch 与本地缓存):
String path = "/config/prod/appA/db";
ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 30000, event -> {
if (event.getType() == Event.EventType.NodeDataChanged) {
reload(); // 重新拉取并刷新内存
}
});
void reload() {
byte[] data = zk.getData(path, true, null); // true=重新注册Watcher
localCache.put("db", new String(data));
}
版本控制与回滚策略(利用 data 记录版本号):
# 写入版本号+配置
set /config/prod/appA/db '{"ver":3,"url":"jdbc:mysql://10.0.0.11:3306/appA"}'
# 预留历史节点用于回滚
create /config/prod/appA/db_hist/v2 '{"ver":2,"url":"jdbc:mysql://10.0.0.10:3306/appA"}'
权限控制示例(只允许运维写):
# 设置 digest ACL:user:pass
addauth digest ops:StrongPass!
setAcl /config/prod/appA/db auth:ops:StrongPass!:cdrwa
getAcl /config/prod/appA/db
常用命令与解释:
# 读取节点
get /config/prod/appA/db
# 监听数据变化(一次性)
get -w /config/prod/appA/db
# 监听子节点变化
ls -w /config/prod/appA
# 修改配置
set /config/prod/appA/db "jdbc:mysql://10.0.0.12:3306/appA"
排错与恢复要点:
- Watcher 未触发:确认使用 get -w/ls -w,且回调中已重新注册;重连后需全量同步。
- 会话过期:应用日志出现 SessionExpired,需重新创建 ZooKeeper 实例并拉取全量配置。
- 数据未更新:检查 ACL 是否限制写入,getAcl 与 addauth 是否一致。
- 通知风暴:对高频变更设置最小变更间隔,或采用“变更服务通知 + 应用拉取”模式。
练习任务:
1. 设计 /config/{env}/{app}/{module} 目录并创建 3 个环境配置。
2. 在两个终端分别执行 get -w 与 set,观察 Watcher 触发。
3. 实现一个简单脚本,每次触发后自动 rewatch 并写入本地缓存文件。
4. 为 /config/prod/appA 配置 ACL,只允许 ops 用户写入,验证普通用户写入失败。