上篇我们说到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 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐