在上一篇文章中,跟踪了基于ZooKeeper
的数据同步原理,本篇文件将要跟踪基于Nacos
的数据同步原理。
同步的核心逻辑是:在soul-admin
后台修改数据,先保存到数据库;然后将修改的信息通过同步策略发送到soul
网关;由网关处理后,保存在soul
网关内存;使用时,从网关内存获取数据。
本文的分析是想通过跟踪源码的方式来理解同步的核心逻辑,数据同步分析步骤如下:
- 1.修改规则
- 2.更新数据
- 3.接受数据
- 4.使用更新后的数据
1. 修改规则
在演示案例之前,将soul-admin
的数据同步方式配置为nacos
(nacos
的启动方式:nacos-server-2.0.0-ALPHA.2\nacos\bin>startup.cmd -m standalone
):
soul:
database:
dialect: mysql
init_script: "META-INF/schema.sql"
init_enable: true
sync:
# websocket:
# enabled: true
# zookeeper:
# url: localhost:2181
# sessionTimeout: 5000
# connectionTimeout: 2000
# http:
# enabled: true
nacos:
url: localhost:8848
namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
acm:
enabled: false
endpoint: acm.aliyun.com
namespace:
accessKey:
secretKey:
在soul-bootstrap
也配置一下数据同步方式为nacos
:
soul :
file:
enabled: true
corss:
enabled: true
dubbo :
parameter: multi
sync:
# websocket :
# urls: ws://localhost:9095/websocket
# zookeeper:
# url: localhost:2181
# sessionTimeout: 5000
# connectionTimeout: 2000
# http:
# url : http://localhost:9095
nacos:
url: localhost:8848
namespace: 1c10d748-af86-43b9-8265-75f487d20c6c
acm:
enabled: false
endpoint: acm.aliyun.com
namespace:
accessKey:
secretKey:
现在,我们以一个实际调用过程为例,比如在Soul
网关管理系统中,对选择器的配置信息进行修改:查询条件中id=99
才能匹配成功。具体信息如下所示:
点击确认后,进入到soul-admin
的updateSelector()
这个接口。
@PutMapping("/{id}")
public SoulAdminResult updateSelector(@PathVariable("id") final String id, @RequestBody final SelectorDTO selectorDTO) {
Objects.requireNonNull(selectorDTO);
selectorDTO.setId(id);
Integer updateCount = selectorService.createOrUpdate(selectorDTO);
return SoulAdminResult.success(SoulResultMessage.UPDATE_SUCCESS, updateCount);
}
2.更新数据
进入到后端系统后,会现在数据中更新信息,然后通过publishEvent()
方法将更新的信息同步到网关。(下面代码只是展示了主要的逻辑,完整的代码请参考Soul
源码。)
@Transactional(rollbackFor = RuntimeException.class)
public int createOrUpdate(final SelectorDTO selectorDTO) {
int selectorCount;
SelectorDO selectorDO = SelectorDO.buildSelectorDO(selectorDTO);
//将更新的数据保存到soul-admin的数据库
//省略了其他代码
//将更新的数据同步到网关
publishEvent(selectorDO, selectorConditionDTOs);
return selectorCount;
}
在publishEvent()
方法中调用了eventPublisher.publishEvent()
,这个eventPublisher
对象是一个ApplicationEventPublisher
类,这个类的全限定名是org.springframework.context.ApplicationEventPublisher
。看到这儿,我们知道了发布数据是通过Spring
相关的功能来完成的。
private void publishEvent(final RuleDO ruleDO, final List<RuleConditionDTO> ruleConditions) {
//省略了其他代码......
// publish change event.
eventPublisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, DataEventTypeEnum.UPDATE,
Collections.singletonList(RuleDO.transFrom(ruleDO, pluginDO.getName(), conditionDataList))));