ShardingJdbc 读写分离源码浅析

项目中使用了SJ,但是只用到了读写分离的部分功能。
在看源码中觉得其中的那个轮循的算法写的比较有意思,这里标记一下。

首先通过MasterSlaveDataSourceFactory来创建DataSource:

public MasterSlaveDataSource(final Map<String, DataSource> dataSourceMap, final MasterSlaveRuleConfiguration masterSlaveRuleConfig,
                                 final Map<String, Object> configMap, final Properties props) throws SQLException {
        super(getAllDataSources(dataSourceMap, masterSlaveRuleConfig.getMasterDataSourceName(), masterSlaveRuleConfig.getSlaveDataSourceNames()));
        if (!configMap.isEmpty()) {
            ConfigMapContext.getInstance().getMasterSlaveConfig().putAll(configMap);
        }
        this.dataSourceMap = dataSourceMap;
        this.masterSlaveRule = new MasterSlaveRule(masterSlaveRuleConfig);
        shardingProperties = new ShardingProperties(null == props ? new Properties() : props);
    }

这里通过将配置的主从DataSourrce信息和主从规则等信息传递进来,其中对DataSource没有什么要求,笔者项目中用的是阿里的Druid,这些都无关紧要。

this.masterSlaveRule = new MasterSlaveRule(masterSlaveRuleConfig);

这里创建了一个主从规则的对象,我们从这里深入:

public MasterSlaveRule(final MasterSlaveRuleConfiguration config) {
        Preconditions.checkNotNull(config.getName(), "Master-slave rule name cannot be null.");
        Preconditions.checkNotNull(config.getMasterDataSourceName(), "Master data source name cannot be null.");
        Preconditions.checkNotNull(config.getSlaveDataSourceNames(), "Slave data source names cannot be null.");
        Preconditions.checkState(!config.getSlaveDataSourceNames().isEmpty(), "Slave data source names cannot be empty.");
        name = config.getName();
        masterDataSourceName = config.getMasterDataSourceName();
        slaveDataSourceNames = config.getSlaveDataSourceNames();
        loadBalanceAlgorithm = null == config.getLoadBalanceAlgorithm() ? MasterSlaveLoadBalanceAlgorithmType.getDefaultAlgorithmType().getAlgorithm() : config.getLoadBalanceAlgorithm();
    }

这里在最后有一个数据源选择的负载均衡算法设置

public enum MasterSlaveLoadBalanceAlgorithmType {
    
    ROUND_ROBIN(new RoundRobinMasterSlaveLoadBalanceAlgorithm()),
    RANDOM(new RandomMasterSlaveLoadBalanceAlgorithm());
    
    private final MasterSlaveLoadBalanceAlgorithm algorithm;
    
    /**
     * Get default master-slave database load-balance algorithm type.
     * 
     * @return default master-slave database load-balance algorithm type
     */
    public static MasterSlaveLoadBalanceAlgorithmType getDefaultAlgorithmType() {
        return ROUND_ROBIN;
    }
}

这里目前只给了两个默认的实现,一个是随机,一个是ROUND_ROBIN。

这里如果用户觉得这个不能满足自己业务场景的需求,可以实现

MasterSlaveLoadBalanceAlgorithmType接口,自定义选择算法

 

public enum MasterSlaveLoadBalanceAlgorithmType {
    
    ROUND_ROBIN(new RoundRobinMasterSlaveLoadBalanceAlgorithm()),
    RANDOM(new RandomMasterSlaveLoadBalanceAlgorithm());
    
    private final MasterSlaveLoadBalanceAlgorithm algorithm;
    
    /**
     * Get default master-slave database load-balance algorithm type.
     * 
     * @return default master-slave database load-balance algorithm type
     */
    public static MasterSlaveLoadBalanceAlgorithmType getDefaultAlgorithmType() {
        return ROUND_ROBIN;
    }
}

下面分别看一下默认提供的两种算法的实现:

  • 随机
public final class RandomMasterSlaveLoadBalanceAlgorithm implements MasterSlaveLoadBalanceAlgorithm {
    
    @Override
    public String getDataSource(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames) {
        return slaveDataSourceNames.get(new Random().nextInt(slaveDataSourceNames.size()));
    }
}

这里就是Random.nextInt , 没有太多解释的

  • ROUND_ROBIN
public final class RoundRobinMasterSlaveLoadBalanceAlgorithm implements MasterSlaveLoadBalanceAlgorithm {
    
    private static final ConcurrentHashMap<String, AtomicInteger> COUNT_MAP = new ConcurrentHashMap<>();
    
    @Override
    public String getDataSource(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames) {
        AtomicInteger count = COUNT_MAP.containsKey(name) ? COUNT_MAP.get(name) : new AtomicInteger(0);
        COUNT_MAP.putIfAbsent(name, count);
        count.compareAndSet(slaveDataSourceNames.size(), 0);
        return slaveDataSourceNames.get(count.getAndIncrement() % slaveDataSourceNames.size());
    }
}

十分的轻量级,很巧妙。

posted @ 2020-03-13 18:10  SyrupzZ  阅读(514)  评论(0)    收藏  举报