引言
在《配置同步》一篇我们提到,Soul 支持 zookeeper 同步策略,今天我们就来探究 Soul 是如何实现该同步策略的。
启用策略
soul-admin
端:
1)开启 zookeeper 同步配置
soul:
sync:
zookeeper:
url: localhost:2181
sessionTimeout: 5000
connectionTimeout: 2000
soul-bootstrap
端:
1)引入 zookeeper 同步依赖:
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-sync-data-zookeeper</artifactId>
<version>2.2.0</version>
</dependency>
2)添加 zookeeper 同步配置:
zookeeper:
url: localhost:2181
sessionTimeout: 5000
connectionTimeout: 2000
同步原理
zookeeper 策略的同步原理:
soul-admin
端:启动时向 zookeeper 写入全量数据,后续数据变更时增量更新。
soul-web
端:依赖 zookeeper 的 watch 机制,监听配置信息的节点,节点变更时更新本地缓存。
源码实现
soul-admin 更新配置节点
ZookeeperDataChangedListener 类实现了 DataChangedListener 接口,监听数据的变化,并通过 zkClient 将数据的变化增量更新到 zookeeper的节点。
public void onApplicationEvent(final DataChangedEvent event) {
for (DataChangedListener listener : listeners) {
switch (event.getGroupKey()) {
case APP_AUTH:
listener.onAppAuthChanged((List<AppAuthData>) event.getSource(), event.getEventType());
break;
case PLUGIN:
listener.onPluginChanged((List<PluginData>) event.getSource(), event.getEventType());
break;
case RULE:
listener.onRuleChanged((List<RuleData>) event.getSource(), event.getEventType());
break;
case SELECTOR:
listener.onSelectorChanged((List<SelectorData>) event.getSource(), event.getEventType());
break;
case META_DATA:
listener.onMetaDataChanged((List<MetaData>) event.getSource(), event.getEventType());
break;
default:
throw new IllegalStateException("Unexpected value: " + event.getGroupKey());
}
}
}
Zookeeper 监听器的初始化:
@Configuration
@ConditionalOnProperty(prefix = "soul.sync.zookeeper", name = "url")
@Import(ZookeeperConfiguration.class)
static class ZookeeperListener {
@Bean
@ConditionalOnMissingBean(ZookeeperDataChangedListener.class)
public DataChangedListener zookeeperDataChangedListener(final ZkClient zkClient) {
return new ZookeeperDataChangedListener(zkClient);
}
@Bean
@ConditionalOnMissingBean(ZookeeperDataInit.class)
public ZookeeperDataInit zookeeperDataInit(final ZkClient zkClient, final SyncDataService syncDataService) {
return new ZookeeperDataInit(zkClient, syncDataService);
}
}
soul-web watch配置节点变更
1、通过 soul-bootstrap
引入 soul-spring-boot-starter-sync-data-zookeeper
依赖
2、spring.factories 指定自动配置类 ZookeeperSyncDataConfiguration:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.dromara.soul.spring.boot.sync.data.zookeeper.ZookeeperSyncDataConfiguration
3、ZookeeperSyncDataConfiguration 自动装载bean时,创建 ZkClient 和 ZookeeperSyncDataService
4、ZookeeperSyncDataService 监听 zookeeper 中选择器、规则、元数据、用户权限等数据的变更。
如何监听:通过 ZkClient 订阅 zookeeper 数据的变化,实现监听并处理变化的数据。
public void subscribeDataChanges(String path, IZkDataListener listener) {
synchronized(this._dataListener) {
Set<IZkDataListener> listeners = (Set)this._dataListener.get(path);
if (listeners == null) {
listeners = new CopyOnWriteArraySet();
this._dataListener.put(path, listeners);
}
((Set)listeners).add(listener);
}
this.watchForData(path);
LOG.debug("Subscribed data changes for " + path);
}