配置中心是微服务架构中的基础设施组件,负责集中管理所有服务的配置信息。在IMS系统中,配置中心需要支持动态配置推送、灰度发布、配置加密、版本回滚等核心能力,确保配置变更安全可控。
配置中心架构
核心数据模型
// 配置中心核心模型
class ConfigCenter {
constructor() {
this.namespaces = new Map(); // 命名空间
this.configs = new Map(); // 配置项 key -> ConfigItem
this.releases = []; // 发布历史
this.watchers = new Map(); // 监听者
}
// 创建命名空间
createNamespace(name, owner) {
this.namespaces.set(name, {
name,
owner,
createdAt: new Date(),
configs: new Map()
});
}
// 设置配置项
setConfig(namespace, key, value, options = {}) {
const ns = this.namespaces.get(namespace);
if (!ns) throw new Error(`命名空间不存在: ${namespace}`);
const configKey = `${namespace}:${key}`;
const configItem = {
key,
value,
type: options.type || detectType(value),
encrypted: options.encrypted || false,
comment: options.comment || '',
version: (this.configs.get(configKey)?.version || 0) + 1,
updatedAt: new Date(),
updatedBy: options.operator || 'system'
};
this.configs.set(configKey, configItem);
ns.configs.set(key, configItem);
// 通知监听者
this.notifyWatchers(configKey, configItem);
return configItem;
}
// 获取配置项
getConfig(namespace, key) {
const configKey = `${namespace}:${key}`;
const item = this.configs.get(configKey);
if (!item) return null;
// 解密加密配置
if (item.encrypted) {
return {
...item,
value: decrypt(item.value)
};
}
return item;
}
}
配置存储设计
// 多级缓存 + 持久化存储
class ConfigStorage {
constructor() {
this.memoryCache = new Map(); // 本地内存缓存
this.redisCache = null; // Redis分布式缓存
this.database = null; // MySQL持久化
}
async get(key) {
// L1: 内存缓存
if (this.memoryCache.has(key)) {
return this.memoryCache.get(key);
}
// L2: Redis缓存
const redisValue = await this.redisCache.get(`config:${key}`);
if (redisValue) {
const parsed = JSON.parse(redisValue);
this.memoryCache.set(key, parsed);
return parsed;
}
// L3: 数据库
const dbValue = await this.database.findOne({
table: 'configs',
where: { key }
});
if (dbValue) {
// 回填缓存
this.memoryCache.set(key, dbValue);
await this.redisCache.set(
`config:${key}`,
JSON.stringify(dbValue),
'EX', 3600
);
}
return dbValue;
}
async set(key, value) {
// 写入数据库
await this.database.upsert('configs', { key, value });
// 更新Redis
await this.redisCache.set(
`config:${key}`,
JSON.stringify(value),
'EX', 3600
);
// 更新内存缓存
this.memoryCache.set(key, value);
}
// 批量加载配置
async loadNamespace(namespace) {
const configs = await this.database.find({
table: 'configs',
where: { namespace }
});
for (const config of configs) {
this.memoryCache.set(config.key, config);
}
return configs;
}
}
动态配置推送
长轮询与WebSocket
// 配置变更推送服务
class ConfigPushService {
constructor() {
this.clients = new Map(); // clientId -> WebSocket
this.subscriptions = new Map(); // key -> Set<clientId>
}
// 客户端连接
onConnect(clientId, ws) {
this.clients.set(clientId, {
ws,
subscriptions: new Set(),
connectedAt: new Date()
});
ws.on('message', (msg) => {
const data = JSON.parse(msg);
this.handleMessage(clientId, data);
});
ws.on('close', () => {
this.onDisconnect(clientId);
});
}
handleMessage(clientId, data) {
switch (data.type) {
case 'subscribe':
this.subscribe(clientId, data.keys);
break;
case 'unsubscribe':
this.unsubscribe(clientId, data.keys);
break;
}
}
// 订阅配置变更
subscribe(clientId, keys) {
const client = this.clients.get(clientId);
for (const key of keys) {
client.subscriptions.add(key);
if (!this.subscriptions.has(key)) {
this.subscriptions.set(key, new Set());
}
this.subscriptions.get(key).add(clientId);
}
}
// 推送配置变更
pushConfigChange(key, value, version) {
const subscribers = this.subscriptions.get(key);
if (!subscribers) return;
const message = JSON.stringify({
type: 'config_change',
key,
value,
version,
timestamp: Date.now()
});
for (const clientId of subscribers) {
const client = this.clients.get(clientId);
if (client && client.ws.readyState === 1) {
client.ws.send(message);
}
}
}
}
// 客户端SDK
class ConfigClient {
constructor(options) {
this.serverUrl = options.serverUrl;
this.appId = options.appId;
this.cache = new Map();
this.listeners = new Map();
this.ws = null;
}
async start() {
// 1. 拉取全量配置
await this.fetchConfigs();
// 2. 建立WebSocket连接
this.connect();
}
connect() {
this.ws = new WebSocket(`${this.serverUrl}/ws?appId=${this.appId}`);
this.ws.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.type === 'config_change') {
this.cache.set(msg.key, msg.value);
this.notifyListeners(msg.key, msg.value);
}
});
this.ws.on('close', () => {
// 自动重连
setTimeout(() => this.connect(), 3000);
});
}
onChange(key, callback) {
if (!this.listeners.has(key)) {
this.listeners.set(key, []);
}
this.listeners.get(key).push(callback);
}
notifyListeners(key, value) {
const cbs = this.listeners.get(key) || [];
for (const cb of cbs) {
cb(value);
}
}
}
灰度发布
配置灰度策略
// 灰度发布管理
class GrayReleaseManager {
constructor() {
this.grayRules = new Map();
}
// 创建灰度规则
createGrayRule(configKey, rule) {
const grayRule = {
configKey,
newValue: rule.newValue,
strategy: rule.strategy, // 'percentage' | 'ip' | 'server'
match: rule.match,
status: 'pending', // pending | running | completed | cancelled
createdAt: new Date()
};
this.grayRules.set(configKey, grayRule);
return grayRule;
}
// 判断是否命中灰度
matchGray(configKey, context) {
const rule = this.grayRules.get(configKey);
if (!rule || rule.status !== 'running') return null;
switch (rule.strategy) {
case 'percentage':
// 按百分比灰度
const hash = hashString(context.clientId) % 100;
return hash < rule.match.percentage
? rule.newValue : null;
case 'ip':
// 按IP灰度
return rule.match.ips.includes(context.ip)
? rule.newValue : null;
case 'server':
// 按服务实例灰度
return rule.match.servers.includes(context.serverId)
? rule.newValue : null;
default:
return null;
}
}
// 全量发布
async promoteToFull(configKey) {
const rule = this.grayRules.get(configKey);
if (!rule) throw new Error('灰度规则不存在');
// 将灰度值设为正式值
await configCenter.setConfig(
...configKey.split(':'),
rule.newValue,
{ operator: 'gray-promote' }
);
rule.status = 'completed';
}
}
配置加密
敏感配置加密存储
// 配置加密服务
class ConfigEncryption {
constructor(options) {
this.algorithm = options.algorithm || 'aes-256-gcm';
this.masterKey = options.masterKey;
}
// 加密配置值
encrypt(plaintext) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(
this.algorithm, this.masterKey, iv
);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted: `ENC(${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted})`,
algorithm: this.algorithm
};
}
// 解密配置值
decrypt(encryptedStr) {
const match = encryptedStr.match(/^ENC\((.+):(.+):(.+)\)$/);
if (!match) return encryptedStr;
const [, ivHex, tagHex, data] = match;
const iv = Buffer.from(ivHex, 'hex');
const authTag = Buffer.from(tagHex, 'hex');
const decipher = crypto.createDecipheriv(
this.algorithm, this.masterKey, iv
);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(data, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
// 敏感配置标记
const sensitiveKeys = [
'password',
'secret',
'token',
'apiKey',
'privateKey',
'database.url'
];
function isSensitiveKey(key) {
return sensitiveKeys.some(s =>
key.toLowerCase().includes(s.toLowerCase())
);
}
版本管理
配置版本与回滚
// 配置版本管理
class ConfigVersionManager {
constructor() {
this.history = new Map(); // key -> VersionRecord[]
}
// 记录版本
recordVersion(key, value, operator) {
if (!this.history.has(key)) {
this.history.set(key, []);
}
const versions = this.history.get(key);
const version = versions.length + 1;
versions.push({
version,
value,
operator,
timestamp: new Date(),
changeType: 'update'
});
return version;
}
// 回滚到指定版本
async rollback(key, targetVersion) {
const versions = this.history.get(key);
if (!versions) throw new Error('无版本历史');
const target = versions.find(v => v.version === targetVersion);
if (!target) throw new Error(`版本 ${targetVersion} 不存在`);
// 恢复到目标版本
await configCenter.setConfig(
...key.split(':'),
target.value,
{
operator: `rollback-to-v${targetVersion}`,
comment: `回滚到版本 ${targetVersion}`
}
);
// 记录回滚操作
this.recordVersion(key, target.value, 'rollback');
}
// 获取版本差异
diff(key, fromVersion, toVersion) {
const versions = this.history.get(key);
const from = versions.find(v => v.version === fromVersion);
const to = versions.find(v => v.version === toVersion);
return {
key,
from: { version: fromVersion, value: from.value },
to: { version: toVersion, value: to.value },
changed: from.value !== to.value
};
}
}
IMS系统典型配置
核心配置项
// IMS系统核心配置模板
const imsConfigTemplate = {
// 应用配置
app: {
name: 'ims-core',
port: 3000,
env: 'production',
logLevel: 'info'
},
// 数据库配置(加密)
database: {
host: 'rm-xxx.mysql.rds.aliyuncs.com',
port: 3306,
name: 'ims_prod',
username: 'ims_app',
password: 'ENC(xxx)', // 加密
poolSize: 20,
timeout: 30000
},
// Redis配置
redis: {
host: 'r-xxx.redis.rds.aliyuncs.com',
port: 6379,
password: 'ENC(xxx)', // 加密
db: 0,
poolSize: 10
},
// 消息队列配置
mq: {
type: 'rabbitmq',
url: 'amqp://ims:ENC(xxx)@mq.internal',
exchange: 'ims.events',
prefetch: 50
},
// 业务开关
features: {
enableWorkflow: true,
enableFormDesigner: true,
enableDataExport: true,
maxExportRows: 100000,
enableAuditLog: true
}
};
总结
- 集中管理 - 统一管理所有服务配置,支持命名空间隔离
- 动态推送 - 基于WebSocket实现配置变更实时推送,客户端无感更新
- 灰度发布 - 支持按百分比、IP、服务实例的灰度策略,降低变更风险
- 配置加密 - 敏感配置加密存储,运行时动态解密
- 版本管理 - 完整的版本历史,支持一键回滚与差异对比
- 多级缓存 - 内存+Redis+数据库三级缓存,保证读取性能
配置中心是微服务架构的基石,完善的配置管理能力让IMS系统运维更加高效安全。