使用Sentinel规则持久化后,新增规则时导致旧规则丢失问题排查
Sentinel
alibaba/Sentinel: Sentinel 是阿里巴巴开源的一款面向分布式服务架构的流量控制、熔断降级组件,提供实时监控、限流、降级和系统保护功能,适用于微服务治理场景。
项目地址:https://gitcode.com/gh_mirrors/sentine/Sentinel
免费下载资源
·
上篇我们说到Sentinel控制台规则双向持久化,这一块是没毛病的,防止应用重启配置丢失。
但是我在测试的时候发现,规则持久化之后,重启控制台新增规则的时候会导致一些之前持久化的数据丢失,究竟发生了什么,我们一起来看下:
首先看看我们初始化拉取规则sentinel做了什么(找到 /list.json API)?
//拉取配置中心规则列表
List<GatewayFlowRuleEntity> rules = ruleProvider.getRules(app);
//保存在内存中
repository.saveAll(rules);
注意清看saveAll方法
@Override
public List<T> saveAll(List<T> rules) {
//清空内存
allRules.clear();
machineRules.clear();
appRules.clear();
if (rules == null) {
return null;
}
List<T> savedRules = new ArrayList<>(rules.size());
for (T rule : rules) {
//遍历放入内存
savedRules.add(save(rule));
}
return savedRules;
}
@Override
public T save(T entity) {
if (entity.getId() == null) { //如果为null就会生成一个Id
//着重看这个方法
entity.setId(nextId());
}
T processedEntity = preProcess(entity);
if (processedEntity != null) {
allRules.put(processedEntity.getId(), processedEntity);
machineRules.computeIfAbsent(MachineInfo.of(processedEntity.getApp(), processedEntity.getIp(),
processedEntity.getPort()), e -> new ConcurrentHashMap<>(32))
.put(processedEntity.getId(), processedEntity);
appRules.computeIfAbsent(processedEntity.getApp(), v -> new ConcurrentHashMap<>(32))
.put(processedEntity.getId(), processedEntity);
}
return processedEntity;
}
//使用的是java jdk的Atomiclong自增,初始化0,也就是说每次应用重启都会把这个清空,从0开始
private static AtomicLong ids = new AtomicLong(0);
@Override
protected long nextId() {
return ids.incrementAndGet();
}
现在是不是已经明白了呢,我们看规则新增方法(找到 /new.json API):
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
//保存至内存
entity = repository.save(entity);
} catch (Throwable throwable) {
logger.error("add gateway api error:", throwable);
return Result.ofThrowable(-1, throwable);
}
try {
publishApis(app, ip, port);
} catch (Exception e) {
e.printStackTrace();
logger.warn("publish gateway apis fail after add");
}
private void publishApis(String app, String ip, Integer port) throws Exception {
//从内存Map获取规则列表
List<ApiDefinitionEntity> apis = repository.findAllByMachine(MachineInfo.of(app, ip, port));
//推送至配置中心
apiPublisher.publish(app, apis);
}
也就是说,推送到配置中心的时候是整个对象,包含AtomicLong生成的Id。
举个例子,现在就是创建了三个规则,Id根据AtomicLong生成为:id=1、id=2、id=3,那么推送去配置中心也会把Id同步过去,当Sentinel控制台重启,AtomicLong清零了,那么你新增规则的时候将会重新自增id=1,就会将之前的持久化好的id为1的覆盖了。
改造,其实就是就修改实现类:
/**
* 如果内存中的Id和规则中最大值的Id不相等,则以规则列表中的最大值Id为初始值
* @param id
*/
public void setMaxID(long id) {
if(id != ids.get()) {
ids = new AtomicLong(id);
}
}
在 /list.json API添加
List<ApiDefinitionEntity> apis = apiProvider.getRules(app);
repository.saveAll(apis);
if(!CollectionUtils.isEmpty(apis)) {
//获取最大值Id
Long id = apis.stream().max(Comparator.comparing(ApiDefinitionEntity::getId)).get().getId();
repository.setMaxID(id);
}
return Result.ofSuccess(apis);
这是我的方法解决,如果能帮助到你,请三连,当然你们有更好的方法请在评论区讨论。
我还是会撩头发的程序猿~
GitHub 加速计划 / sentine / Sentinel
22.24 K
7.98 K
下载
alibaba/Sentinel: Sentinel 是阿里巴巴开源的一款面向分布式服务架构的流量控制、熔断降级组件,提供实时监控、限流、降级和系统保护功能,适用于微服务治理场景。
最近提交(Master分支:3 个月前 )
195150bc
* fix issue 2485 which occur oom when using async servlet request.
* optimize imports
* 1. fix the same issue in the webmvc-v6x
2. improve based on review comments 2 个月前
b78b09d3
2 个月前
更多推荐
已为社区贡献1条内容
所有评论(0)