读写分离功能作为shardingsphere的可插拔能力之一
api:对外暴露的接口,包括算法spi、配置的对象类
core:核心层,包含默认提供的读分配的负载均衡的算法、以及SQL改写,选取数据源的核心逻辑
distSQL:distsql解析以及管理的相关的流程
spring:spring-boot-starter以及spring-namespace相关的实现。
在api层面,对外提供的主要是配置对象以及,读的负载均衡。
在这里,官方提供了两种方式的负载。
1、ROUND_ROBIN(默认算法)
核心实现:
private static final ConcurrentHashMap<String, AtomicInteger> COUNTS = new ConcurrentHashMap<>(); @Override public String getDataSource(final String name, final String writeDataSourceName, final List<String> readDataSourceNames) { AtomicInteger count = COUNTS.containsKey(name) ? COUNTS.get(name) : new AtomicInteger(0); COUNTS.putIfAbsent(name, count); count.compareAndSet(readDataSourceNames.size(), 0); return readDataSourceNames.get(Math.abs(count.getAndIncrement()) % readDataSourceNames.size()); }
2、RANDOM
@Override public String getDataSource(final String name, final String writeDataSourceName, final List<String> readDataSourceNames) { return readDataSourceNames.get(ThreadLocalRandom.current().nextInt(readDataSourceNames.size())); }
通过下述逻辑获取对应的读或者写的数据源。
/** * Route. * * @param sqlStatement SQL statement * @return data source name */ public String route(final SQLStatement sqlStatement) { if (isPrimaryRoute(sqlStatement)) { String autoAwareDataSourceName = rule.getAutoAwareDataSourceName(); if (Strings.isNullOrEmpty(autoAwareDataSourceName)) { return rule.getWriteDataSourceName(); } Optional<DataSourceNameAware> dataSourceNameAware = DataSourceNameAwareFactory.getInstance().getDataSourceNameAware(); if (dataSourceNameAware.isPresent()) { return dataSourceNameAware.get().getPrimaryDataSourceName(autoAwareDataSourceName); } } String autoAwareDataSourceName = rule.getAutoAwareDataSourceName(); if (Strings.isNullOrEmpty(autoAwareDataSourceName)) { return rule.getLoadBalancer().getDataSource(rule.getName(), rule.getWriteDataSourceName(), rule.getReadDataSourceNames()); } Optional<DataSourceNameAware> dataSourceNameAware = DataSourceNameAwareFactory.getInstance().getDataSourceNameAware(); if (dataSourceNameAware.isPresent()) { Collection<String> replicaDataSourceNames = dataSourceNameAware.get().getReplicaDataSourceNames(autoAwareDataSourceName); return rule.getLoadBalancer().getDataSource(rule.getName(), rule.getWriteDataSourceName(), new ArrayList<>(replicaDataSourceNames)); } return rule.getLoadBalancer().getDataSource(rule.getName(), rule.getWriteDataSourceName(), rule.getReadDataSourceNames()); } private boolean isPrimaryRoute(final SQLStatement sqlStatement) { return containsLockSegment(sqlStatement) || !(sqlStatement instanceof SelectStatement) || HintManager.isWriteRouteOnly() || TransactionHolder.isTransaction(); }