9.5 KiB
9.5 KiB
Consul KV 配置中心方案
文档版本:v1.0
创建日期:2025-12-16
负责项目:customerservice + message + gateway
一、核心目标
| 目标 | 说明 |
|---|---|
| 安全性 | 敏感配置(连接地址/密码)不写在代码里,从 Consul KV 读取 |
| 回退机制 | Consul 不可用时,使用本地默认配置保证服务可启动 |
| 热更新 | Consul KV 变更后,服务无需重启立即生效 |
| 性能最优 | 请求路径只读内存(原子快照),不访问 Consul;单协程阻塞监听,不空转 |
二、配置分类与热更新策略
2.1 配置分类
| 分类 | 配置项 | 热更新方式 |
|---|---|---|
| 连接池配置 | http 连接池数量、redis 连接池数量、mongo 连接池数量 | 平滑切换(创建新池→原子替换→延迟关闭旧池) |
| 协程池配置 | grpool worker 数量 | 动态调整(grpool.SetSize()) |
| 业务参数 | 追问延时、归档延时、批量大小、超时时间、卡片触发轮数 | 直接原子更新内存变量 |
| 开关/限流 | 功能开关、限流阈值、日志级别 | 直接原子更新内存变量 |
| 中间件地址 | Redis/MQ/Mongo/ES/Jaeger 地址 | 平滑切换连接池 |
2.2 热更新策略矩阵
┌─────────────────────────────────────────────────────────────────┐
│ 热更新策略矩阵 │
├─────────────────────────────────────────────────────────────────┤
│ 配置变更类型 │ 更新方式 │ 对请求影响 │
├─────────────────────────────────────────────────────────────────┤
│ 业务参数/开关 │ atomic.Value │ 无影响,立即生效 │
│ 协程池数量 │ grpool.SetSize │ 无影响,渐进生效 │
│ 连接池数量/地址 │ 平滑切换单例 │ 无影响,新请求用新池 │
└─────────────────────────────────────────────────────────────────┘
三、Consul KV 键名规范
config/{service}/pool
config/{service}/business
config/{service}/middleware
3.1 示例 KV 结构
Key: config/customerservice/pool
http:
maxConns: 100 # HTTP 连接池最大连接数
maxIdleConns: 20 # HTTP 连接池最大空闲连接
redis:
maxActive: 50 # Redis 连接池最大活跃连接
maxIdle: 10 # Redis 连接池最大空闲连接
idleTimeout: 300 # 空闲超时(秒)
grpool:
workerSize: 200 # 协程池 worker 数量
Key: config/customerservice/business
followUp:
delay1: 30 # 第一次追问延时(秒)
delay2: 60 # 第二次追问延时(秒)
delay3: 180 # 第三次追问延时(秒)
archive:
delay: 3600 # 归档延时(秒)
stream:
batchSize: 200 # 批量读取消息数量
blockTimeout: 2000 # 阻塞超时(毫秒)
card:
triggerCount: 5 # 触发发送卡片的对话轮数
Key: config/customerservice/middleware
redis:
address: "192.168.3.200:6379"
password: ""
db: 0
rabbitmq:
host: "192.168.3.200"
port: 5672
username: "guest"
password: "guest"
vhost: "/"
mongo:
uri: "mongodb://192.168.3.200:27017"
database: "customer_service"
四、架构设计
4.1 模块结构
consul api 里有个watch , 用watch去做
common/configcenter/
├── configcenter.go # 核心:启动/停止/获取配置
├── watcher.go # Consul KV 阻塞监听(单协程)
├── snapshot.go # 配置快照(atomic.Value)
├── hook.go # 变更回调分发
└── types.go # 配置结构体定义
4.2 核心接口
// 启动配置中心(每个服务 main.go 调用一次)
func Start(ctx context.Context, opts Options) error
// 获取当前配置快照(请求路径调用,O(1) 无锁)
func Get() *Snapshot
// 注册变更回调(组件注册自己的重初始化逻辑)
func Subscribe(name string, handler func(old, new *Snapshot))
// 优雅停止
func Stop()
4.3 数据流
┌──────────────┐ 阻塞查询 ┌──────────────┐
│ Consul KV │ ─────────────→ │ Watcher │ (单协程,不空转)
└──────────────┘ (长轮询) └──────┬───────┘
│ 配置变更
▼
┌──────────────┐
│ Snapshot │ (atomic.Value 原子替换)
└──────┬───────┘
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 业务代码读取 │ │ Hook 回调 │ │ 日志记录 │
│ Get().Pool │ │ 重建连接池 │ │ 版本号变更 │
└────────────────┘ └────────────────┘ └────────────────┘
五、服务启动流程
func main() {
ctx := context.Background()
// 1. 启动配置中心(优先从 Consul 拉取,失败则用本地默认)
if err := configcenter.Start(ctx, configcenter.Options{
ConsulAddr: "192.168.3.200:8500",
ServiceName: "customerservice",
DefaultPath: "config.yml", // 回退配置
}); err != nil {
glog.Warningf(ctx, "配置中心启动失败,使用本地配置: %v", err)
}
// 2. 注册组件热更新回调
configcenter.Subscribe("redis", redis.OnConfigChange)
configcenter.Subscribe("grpool", ragflow.OnPoolSizeChange)
configcenter.Subscribe("rabbitmq", rabbitmq.OnConfigChange)
// 3. 初始化组件(使用 configcenter.Get() 获取配置)
initComponents(ctx)
// 4. 启动服务...
// 5. 优雅退出
defer configcenter.Stop()
}
六、性能保证
| 环节 | 性能策略 |
|---|---|
| 请求路径 | 只读 atomic.Value,O(1),无锁,无网络 |
| 监听 Consul | 阻塞查询(Blocking Query),无变更时不消耗 CPU |
| 配置解析 | 只在变更时解析一次 YAML → 结构体 |
| 连接池切换 | 原子替换指针,旧池延迟 30s 关闭(等待请求完成) |
| 协程池调整 | grpool 内置支持动态调整,无需重建 |
七、回退与容错
| 场景 | 处理方式 |
|---|---|
| 启动时 Consul 不可用 | 使用本地 config.yml 默认配置,服务正常启动 |
| 运行时 Consul 断连 | 保持最后一次成功配置,自动重试连接 |
| 配置格式错误 | 拒绝更新,保持旧配置,记录错误日志 |
| 连接池切换失败 | 保持旧连接池,记录错误,不影响服务 |
八、Consul KV 操作示例
8.1 通过 Consul UI 操作
- 访问
http://192.168.3.200:8500/ui - 点击 Key/Value 菜单
- 创建/编辑 Key,如
config/customerservice/business - 在 Value 中粘贴 YAML 配置内容
- 点击 Save
8.2 通过 CLI 操作
# 写入配置
consul kv put config/customerservice/business @business.yml
# 读取配置
consul kv get config/customerservice/business
# 删除配置
consul kv delete config/customerservice/business
8.3 通过 HTTP API 操作
# 写入配置
curl --request PUT \
--url http://192.168.3.200:8500/v1/kv/config/customerservice/business \
--data-binary @business.yml
# 读取配置(Base64 编码)
curl http://192.168.3.200:8500/v1/kv/config/customerservice/business
# 阻塞查询(长轮询,等待变更)
curl "http://192.168.3.200:8500/v1/kv/config/customerservice/business?index=123&wait=5m"
九、实现进度
| 阶段 | 状态 | 说明 |
|---|---|---|
| 方案设计 | ✅ 完成 | 本文档 |
| common/configcenter 模块 | ⏳ 待实现 | 核心配置中心模块 |
| 各组件热更新回调 | ⏳ 待实现 | Redis/MQ/Mongo/ES 等 |
| 联调验证 | ⏳ 待实现 | KV 修改后无需重启生效 |
十、注意事项
- 安全性:生产环境的 Consul 必须启用 ACL,限制 KV 访问权限
- 版本控制:重要配置变更前,建议先备份旧配置
- 灰度发布:可通过
config/{env}/{service}实现多环境配置隔离 - 监控告警:建议对配置变更事件添加日志和告警