问题提出
Apollo 是携程开源的分布式配置管理中心,用于统一管理和动态更新应用配置,支持多环境、多命名空间、高可用部署,应用通过客户端 SDK 实现实时拉取和热刷新配置,无需重启即可生效,广泛应用于微服务架构中。本文主要就是探讨两种实现热刷新配置的方法:监听器与channel实现。两者主要的区别是:可以把监听器理解为“事件推送”,channel 理解为“事件拉取”
监听器
监听器的方式就是在主函数中注册监听器,apollo配置改变时通知调用监听器,执行是同步还是异步自行斟酌。
// 监听器类型,接收 key 和 change
type ConfigChangeListener func(key string, change *agollo.Change)
// 全局监听器
type ListenerManager struct {
listenersMu sync.RWMutex
listeners []ConfigChangeListener
}
var globalListenerManager = &ListenerManager{}
// 注册监听器
func RegisterListener(listener ConfigChangeListener) {
globalListenerManager.listenersMu.Lock()
defer globalListenerManager.listenersMu.Unlock()
globalListenerManager.listeners = append(globalListenerManager.listeners, listener)
}
// 通知监听器
func notifyListeners(key string, change *agollo.Change) {
globalListenerManager.listenersMu.RLock()
defer globalListenerManager.listenersMu.RUnlock()
for _, listener := range globalListenerManager.listeners {
// 调用每个监听器
listener(key, change)
}
}
// 注册配置变更监听器
apollo.RegisterListener(func(key string, change *agollo.Change) {
if key == consts.HttpClientConfigKey {
// 执行更新操作
}
})
channel实现
用 channel 事件消费机制来实现,是将配置变化封装为事件发送到 channel,客户端通过读取 channel 主动获取并处理配置更新。
type ConfigChangeEvent struct {
Key string
Change agollo.ConfigChange
}
var configChangeChan = make(chan ConfigChangeEvent, 100)
// 将 evt 发送到 channel
evt := ConfigChangeEvent{
Key: key,
Change: change,
}
configChangeChan <- evt
// 将 evt 从 channel 中取出
go func() {
for evt := range configChangeChan {
if evt.Key == consts.HttpClientConfigKey {
// 执行更新操作
}
}
}()