KV存储与配置管理
2026/1/15大约 4 分钟ConsulKV存储配置中心
KV 存储与配置管理
一、KV 存储概述
Consul 提供分布式 Key-Value 存储,可用于:
- 动态配置管理
- 特性开关
- 服务协调
- Leader 选举
1.1 KV 存储特点
二、基本操作
2.1 命令行操作
# 写入键值
consul kv put config/database/host 192.168.1.100
consul kv put config/database/port 3306
# 读取键值
consul kv get config/database/host
# 读取所有键
consul kv get -recurse config/
# 删除键值
consul kv delete config/database/host
# 删除前缀下所有键
consul kv delete -recurse config/database/2.2 HTTP API 操作
# 写入
curl -X PUT -d "192.168.1.100" http://localhost:8500/v1/kv/config/database/host
# 读取
curl http://localhost:8500/v1/kv/config/database/host
# 读取并解码
curl -s http://localhost:8500/v1/kv/config/database/host | jq -r '.[0].Value' | base64 -d
# 列出所有键
curl "http://localhost:8500/v1/kv/config/?keys"
# 递归读取
curl "http://localhost:8500/v1/kv/config/?recurse"
# 删除
curl -X DELETE http://localhost:8500/v1/kv/config/database/host2.3 响应格式
[
{
"LockIndex": 0,
"Key": "config/database/host",
"Flags": 0,
"Value": "MTkyLjE2OC4xLjEwMA==",
"CreateIndex": 100,
"ModifyIndex": 200
}
]三、配置管理
3.1 配置结构设计
config/
├── common/ # 公共配置
│ ├── database
│ └── redis
├── user-service/ # 服务专属配置
│ ├── application.yml
│ └── feature-flags
└── order-service/
├── application.yml
└── feature-flags3.2 存储 YAML 配置
# 存储配置文件
consul kv put config/user-service/application.yml @application.yml
# 或直接写入
consul kv put config/user-service/data '
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/user
username: root
password: secret
'3.3 存储 JSON 配置
consul kv put config/user-service/settings '{
"maxConnections": 100,
"timeout": 30,
"retryCount": 3
}'四、Spring Cloud Consul Config
4.1 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>4.2 配置文件
# bootstrap.yml
spring:
application:
name: user-service
profiles:
active: dev
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
format: YAML
prefix: config
default-context: application
profile-separator: ','
data-key: data4.3 配置加载顺序
4.4 在 Consul 中存储配置
# 应用配置
consul kv put config/user-service/data '
server:
port: 8080
custom:
message: Hello from Consul
'
# 环境配置
consul kv put config/user-service,dev/data '
custom:
message: Hello from Dev
'4.5 使用配置
@RestController
@RefreshScope
public class ConfigController {
@Value("${custom.message}")
private String message;
@GetMapping("/config")
public String getConfig() {
return message;
}
}五、配置动态刷新
5.1 启用 Watch
spring:
cloud:
consul:
config:
watch:
enabled: true
delay: 1000 # 检查间隔(毫秒)5.2 使用 @RefreshScope
@Configuration
@RefreshScope
public class DynamicConfig {
@Value("${feature.newUI:false}")
private boolean newUIEnabled;
@Value("${rate.limit:100}")
private int rateLimit;
public boolean isNewUIEnabled() {
return newUIEnabled;
}
public int getRateLimit() {
return rateLimit;
}
}5.3 监听配置变更
@Component
public class ConfigChangeListener implements ApplicationListener<RefreshScopeRefreshedEvent> {
@Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
System.out.println("Configuration refreshed!");
// 执行配置变更后的逻辑
}
}六、Watch 机制
6.1 HTTP 长轮询
# 阻塞查询,等待变更
curl "http://localhost:8500/v1/kv/config/user-service/data?index=100&wait=5m"6.2 Java Watch 实现
@Component
public class ConsulKVWatcher {
private final ConsulClient consulClient;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
public ConsulKVWatcher(ConsulClient consulClient) {
this.consulClient = consulClient;
}
@PostConstruct
public void startWatch() {
executor.submit(() -> {
long index = 0;
while (true) {
try {
Response<GetValue> response = consulClient.getKVValue(
"config/user-service/data",
new QueryParams(300, index) // 5分钟超时
);
if (response.getConsulIndex() != index) {
index = response.getConsulIndex();
String value = new String(Base64.getDecoder().decode(
response.getValue().getValue()
));
onConfigChange(value);
}
} catch (Exception e) {
Thread.sleep(5000);
}
}
});
}
private void onConfigChange(String newConfig) {
System.out.println("Config changed: " + newConfig);
}
}七、事务操作
7.1 CAS 操作
# 条件更新(只有 ModifyIndex 匹配时才更新)
curl -X PUT -d "new-value" "http://localhost:8500/v1/kv/config/key?cas=200"7.2 事务 API
curl -X PUT http://localhost:8500/v1/txn \
-d '[
{
"KV": {
"Verb": "set",
"Key": "config/key1",
"Value": "dmFsdWUx"
}
},
{
"KV": {
"Verb": "set",
"Key": "config/key2",
"Value": "dmFsdWUy"
}
}
]'7.3 事务操作类型
| Verb | 说明 |
|---|---|
| set | 设置键值 |
| get | 获取键值 |
| delete | 删除键 |
| cas | 条件设置 |
| lock | 获取锁 |
| unlock | 释放锁 |
八、分布式锁
8.1 获取锁
# 创建 Session
SESSION=$(curl -X PUT -d '{"Name": "my-lock", "TTL": "30s"}' \
http://localhost:8500/v1/session/create | jq -r '.ID')
# 获取锁
curl -X PUT "http://localhost:8500/v1/kv/locks/my-resource?acquire=$SESSION"8.2 释放锁
# 释放锁
curl -X PUT "http://localhost:8500/v1/kv/locks/my-resource?release=$SESSION"
# 销毁 Session
curl -X PUT "http://localhost:8500/v1/session/destroy/$SESSION"8.3 Java 分布式锁
@Component
public class ConsulDistributedLock {
private final ConsulClient consulClient;
public ConsulDistributedLock(ConsulClient consulClient) {
this.consulClient = consulClient;
}
public String acquireLock(String lockKey, int ttlSeconds) {
// 创建 Session
NewSession session = new NewSession();
session.setName(lockKey);
session.setTtl(ttlSeconds + "s");
session.setBehavior(Session.Behavior.DELETE);
String sessionId = consulClient.sessionCreate(session, null)
.getValue();
// 尝试获取锁
boolean acquired = consulClient.setKVValue(
"locks/" + lockKey,
"locked",
new PutParams().setAcquireSession(sessionId)
).getValue();
if (acquired) {
return sessionId;
}
// 获取失败,销毁 Session
consulClient.sessionDestroy(sessionId, null);
return null;
}
public void releaseLock(String lockKey, String sessionId) {
consulClient.setKVValue(
"locks/" + lockKey,
"unlocked",
new PutParams().setReleaseSession(sessionId)
);
consulClient.sessionDestroy(sessionId, null);
}
}九、特性开关
9.1 配置特性开关
consul kv put config/features/new-checkout true
consul kv put config/features/dark-mode false
consul kv put config/features/beta-users '["user1","user2"]'9.2 Java 实现
@Component
@RefreshScope
public class FeatureFlags {
@Value("${features.new-checkout:false}")
private boolean newCheckout;
@Value("${features.dark-mode:false}")
private boolean darkMode;
public boolean isNewCheckoutEnabled() {
return newCheckout;
}
public boolean isDarkModeEnabled() {
return darkMode;
}
}
@RestController
public class FeatureController {
@Autowired
private FeatureFlags featureFlags;
@GetMapping("/checkout")
public String checkout() {
if (featureFlags.isNewCheckoutEnabled()) {
return "New checkout flow";
}
return "Legacy checkout flow";
}
}十、最佳实践
10.1 键命名规范
{环境}/{服务名}/{配置类型}/{配置项}
示例:
prod/user-service/database/host
dev/order-service/redis/port10.2 配置版本管理
# 带版本的配置
consul kv put config/user-service/v1/data @config-v1.yml
consul kv put config/user-service/v2/data @config-v2.yml
# 当前版本指针
consul kv put config/user-service/current v210.3 敏感配置加密
@Configuration
public class EncryptedConfigProcessor {
@Value("${encryption.key}")
private String encryptionKey;
public String decrypt(String encryptedValue) {
// 使用 AES 解密
return AESUtil.decrypt(encryptedValue, encryptionKey);
}
}