Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sentinel自行持久化后的一个bug,会导致新增的各类规则把持久数据源加载出来的规则冲掉 #1868

Open
rainy0714 opened this issue Nov 19, 2020 · 5 comments
Labels
area/dashboard Issues or PRs about Sentinel Dashboard

Comments

@rainy0714
Copy link

rainy0714 commented Nov 19, 2020

用nacos做的持久化,至于如何持久化的,网上一堆教程,用的push模式

但是当sentinel重启后,com.alibaba.csp.sentinel.dashboard.repository.rule下的InMemoryRuleRepositoryAdapter中的save方法

@Override
    public T save(T entity) {
        if (entity.getId() == null) {
            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;
    }

给entity赋值的时候,这里用的nextId(),而这个nextId的逻辑是下面这里:

@Component
public class InMemFlowRuleStore extends InMemoryRuleRepositoryAdapter<FlowRuleEntity> {

    private static AtomicLong ids = new AtomicLong(0);

    @Override
    protected long nextId() {
        return ids.incrementAndGet();
    }

    @Override
    protected FlowRuleEntity preProcess(FlowRuleEntity entity) {
        if (entity != null && entity.isClusterMode()) {
            ClusterFlowConfig config = entity.getClusterConfig();
            if (config == null) {
                config = new ClusterFlowConfig();
                entity.setClusterConfig(config);
            }
            // Set cluster rule id.
            config.setFlowId(entity.getId());
        }
        return entity;
    }

所以会导致id直接从1开始赋新的值,而allRules这个Map又会以这个id为key进行规则的存储,导致sentinel重启后,新增的各类规则会逐步将原有规则冲掉了,需要自己修改一下这里的id生成逻辑

@jasonjoo2010
Copy link
Collaborator

其实我一直建议直接在app端同时集成read/write数据源,直接通过原生的dashboard走transport api来改,这样其实没什么改动

@linlinisme
Copy link
Collaborator

+1

@rainy0714
Copy link
Author

其实我一直建议直接在app端同时集成read/write数据源,直接通过原生的dashboard走transport api来改,这样其实没什么改动

的确是个好建议

@HuiBear
Copy link

HuiBear commented Nov 25, 2020

InMemoryRuleRepositoryAdapter类中save方法里添加了一个判断解决了这个问题

代码如下:
@OverRide
public T save(T entity) {
if (entity.getId() == null) {
entity.setId(nextId());
// 先判断entity的Id值做为key是否已在allRules存在
if (!CollectionUtils.isEmpty(allRules) && allRules.get(entity.getId()) != null) {
Long generateId = getMaxKey(allRules);
if (generateId != null) {
entity.setId(generateId + 1);
}
}
}

/**
 * 获得map中最大的key值
 * @param map
 * @return
 */
private Long getMaxKey(Map<Long, T> map) {
    if (CollectionUtils.isEmpty(map)) {
        return null;
    }
    Set<Long> set = map.keySet();
    Object[] obj = set.toArray();
    Arrays.sort(obj);
    return Long.parseLong(obj[obj.length - 1].toString());
}

@bingSea
Copy link

bingSea commented Aug 18, 2021

InMemoryRuleRepositoryAdapter类中save方法里添加了一个判断解决了这个问题

代码如下:
@OverRide
public T save(T entity) {
if (entity.getId() == null) {
entity.setId(nextId());
// 先判断entity的Id值做为key是否已在allRules存在
if (!CollectionUtils.isEmpty(allRules) && allRules.get(entity.getId()) != null) {
Long generateId = getMaxKey(allRules);
if (generateId != null) {
entity.setId(generateId + 1);
}
}
}

/**
 * 获得map中最大的key值
 * @param map
 * @return
 */
private Long getMaxKey(Map<Long, T> map) {
    if (CollectionUtils.isEmpty(map)) {
        return null;
    }
    Set<Long> set = map.keySet();
    Object[] obj = set.toArray();
    Arrays.sort(obj);
    return Long.parseLong(obj[obj.length - 1].toString());
}

@HuiBear
你这样改还是有问题,原因是当点击一个流控规则MaxKey比较小的应用的 流控规则 菜单,此时内存中 allRules 就有值了,然后再给一个流控规则MaxKey比较大的应用添加流控规则,也会出现覆盖的情况,此处bug较难复现,操作关键点在于,在给流控规则MaxKey比较大的应用添加流控规则时,先不要点击它的 流控规则 菜单(此时内存allRules 中保存的还是那个流控规则MaxKey比较小的值),直接从 簇点链路 进去,点击 流控 按钮添加,并且流控规则MaxKey比较大的应用的流控规则id集合中,存在流控规则MaxKey比较小的【MaxKey+1】这个值

注:该 bug 依据源代码1.8.2版本调试发现

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/dashboard Issues or PRs about Sentinel Dashboard
Projects
None yet
Development

No branches or pull requests

6 participants