Soul源码学习 - 数据同步的一个问题记录

环境

今天讨论的版本是2.2.1 - release版本;
soul-admin 和 soul-bootstrap都集群部署

分析

问题

admin在做集群不是的时候,如果用户修改配置,当节点数据只到达其中一个而没有到达其他节点时,其他节点会有一个5分钟的延时。
admin节点和节点之间时互不感知的。

在HttpLongPollingDataChangedListenner 的afterInitialize方法中会通过一个5分钟的定时任务去拉取数据到admin缓存中。

@Override
    protected void afterInitialize() {
    
    
        long syncInterval = httpSyncProperties.getRefreshInterval().toMillis();
        // Periodically check the data for changes and update the cache
        scheduler.scheduleWithFixedDelay(() -> {
    
    
            log.info("http sync strategy refresh config start.");
            try {
    
    
                this.refreshLocalCache();
                log.info("http sync strategy refresh config success.");
            } catch (Exception e) {
    
    
                log.error("http sync strategy refresh config error!", e);
            }
        }, syncInterval, syncInterval, TimeUnit.MILLISECONDS);
        log.info("http sync strategy refresh interval: {}ms", syncInterval);
    }

处理方式

admin,提供2个接口,一个是listener,一个是fetch
1、listener接口,用于hold来自web的http请求,如果没有配置变更,会阻塞http请求,直到超时;如果有配置变更,会响应请求,告诉web是哪个group的配置发生了变更;
2、fetch接口,用于拉取group配置组的数据;

如果有多个Admin, 例如a, b, c三个节点,更新的操作只到达了一个节点;web会监听所有的admin节点,一旦节点有变化,就会收到最新的配置数据,但是某些节点数据,并不是最新的,这样倒置bootstrap拉不到最新的数据,所以bootstrap请求的时候会带上last_update_time 来监听listener,这个时候admin会对比时间戳,如果时间落后了,则更新本地配置数据;

private boolean checkCacheDelayAndUpdate(final ConfigDataCache serverCache, final String clientMd5, final long clientModifyTime) {
    
    

     ...
        long lastModifyTime = serverCache.getLastModifyTime();
        if (lastModifyTime >= clientModifyTime) {
    
    
            // 客户端配置过时了
            return true;
        }

        // the lastModifyTime before client, then the local cache needs to be updated.
        // Considering the concurrency problem, admin must lock,
        // otherwise it may cause the request from soul-web to update the cache concurrently, causing excessive db pressure
        ...
        if (locked) {
    
    
            try {
    
    
                ConfigDataCache latest = CACHE.get(serverCache.getGroup());
                if (latest != serverCache) {
    
    
                    // the cache of admin was updated. if the md5 value is the same, there's no need to update.
                    return !StringUtils.equals(clientMd5, latest.getMd5());
                }
                // 从数据库加载配置到缓存中
                this.refreshLocalCache();
                latest = CACHE.get(serverCache.getGroup());
                return !StringUtils.equals(clientMd5, latest.getMd5());
            } finally {
    
    
                LOCK.unlock();
            }
        }

        ...

    }

猜你喜欢

转载自blog.csdn.net/qq_35115942/article/details/113160824