【源碼解析】Sharding-Jdbc中的算法


Sharding-jdbc中的很多地方涉及到算法,比如主從配置這塊、分庫分表這塊。本文主要從源碼角度介紹下,目前主要包含哪些算法,以及這些算法的內容。

一、讀寫分離(主從配置)

這塊的代碼主要在core模塊中的api/algorithm/masterslave下面,這塊的算法的主要目的,其實是在讀的時候,如何選擇從數據庫。按照常規的理解,可以有以下幾種(參考dubbo):

  • 隨機算法
  • 輪詢
  • 最小活躍
  • 一致性hash

目前在sharding-jdbc中,實現了前兩種,我們看下是如何實現的。

首先是一個接口,定義了獲取slave的方法,即:

public interface MasterSlaveLoadBalanceAlgorithm {
    
    /**
     * Get data source.
     * 
     * @param name master-slave logic data source name
     * @param masterDataSourceName name of master data sources
     * @param slaveDataSourceNames names of slave data sources
     * @return name of selected data source
     */
    String getDataSource(String name, String masterDataSourceName, List<String> slaveDataSourceNames);
}

最終需要返回的是slave的名稱,后續根據這個名稱可以獲取到連接池。

下面我們看下兩種實現:

  • RandomMasterSlaveLoadBalanceAlgorithm
public String getDataSource(final String name, final String masterDataSourceName, final List<String> slaveDataSourceNames) {
    return slaveDataSourceNames.get(new Random().nextInt(slaveDataSourceNames.size()));
}

可以看到,隨機了一個slave集群大小的隨機數,然后從slave list中獲取對應的slave name。

  • RoundRobinMasterSlaveLoadBalanceAlgorithm
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());
}

這塊用了一個緩存,COUNT_MAP,緩存的內容是name-count的鍵值對,而count是一個原子類,它的值一直是0,1,...,slaves.size()-1,0,1..這樣循環,所以每個slave都會被輪詢到。

二、分庫分表

分庫分表的算法目前支持的內容包括:

  • 精確分庫分表PreciseShardingValue
  • 按照范圍分庫分表RangeShardingValue
  • 按照列表分庫分表ListShardingValue

這塊主要是定義了一些接口,具體的實現還是要看自己來實現。我們來看下example中的一些已經實現的算法。

public final class PreciseModuloDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
    
    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Integer> shardingValue) {
        for (String each : availableTargetNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new UnsupportedOperationException();
    }
}

這塊就是實現了一個精准分片的算法,我們主要看下doSharding這個方法,里面包含兩個參數availableTargetNames和shardingValue。那么這兩個是什么呢?我們debug一下,跟蹤一下代碼,可以看到,shardingValue其實就是分片項,也就是比如order_id、user_id等等字段值,而availableTargetNames就是所謂的實際數據庫表節點。這邊遍歷的也是實際節點,當分片項(或分片字段)滿足一定的條件時,返回實際數據庫表節點,用於組裝sql。

總的來說,分片算法這塊其實根據自己的業務需求自己進行擴展的,總的來說還是要根據實際的機器部署情況來。另外讀寫分離這塊是否需要進行擴展,也是看后續的需要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM