Sharding sphere version 4.0.0-rc1 is divided into annual tables (later optimization)

Keywords: Programming Apache Spring JDBC Google

1. Sharding sphere version 4.0.0-rc1 is divided into annual tables (to be optimized later)

1.1. overview

As for the tables of LogShardingAlgorithm in the previous article, I used to initialize them when I called for the first time. Although this can realize the function, I would use this if judgment every time I called. Although the performance loss is not big, I don't think this is the logical order for the business. My ideal is to automatically initialize tables after the LogShardingAlgorithm is instantiated

Now the problem is that the instantiation of LogShardingAlgorithm is executed during Spring initialization, and its creation is not generated by Spring's @ Component and other annotations, but by reflection. If initialization is performed at the beginning of instantiation, that is, when the construction method is executed, the applicationContext has not been initialized, the environment parameters cannot be obtained, and even the Datasource has not been initialized

1.2. Solutions

After transformation, the code is as follows: a single initialization method is singled out, and after the class object is instantiated, it is called.

/**
 * @author: laoliangliang
 * @description: Log fragmentation
 * @create: 2020/1/2 10:19
 **/
@Slf4j
public class LogShardingAlgorithm implements PreciseShardingAlgorithm, RangeShardingAlgorithm<Integer> {

    /**
     * Cache existing tables
     */
    private List<String> tables;

    private final String systemLogHead = "system_log_";

    public void init(){
        tables = DBUtil.getAllSystemLogTable();
    }

    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
        String target = shardingValue.getValue().toString();
        String year = target.substring(target.lastIndexOf("_") + 1, target.lastIndexOf("_") + 5);
        if (!tables.contains(systemLogHead + year)) {
            DBUtil.createLogTable(year);
            tables.add(year);
        }
        return shardingValue.getLogicTableName() + "_" + year;
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Integer> shardingValue) {
        Collection<String> availables = new ArrayList<>();
        Range valueRange = shardingValue.getValueRange();
        for (String target : tables) {
            Integer shardValue = Integer.parseInt(target.substring(target.lastIndexOf("_") + 1, target.lastIndexOf("_") + 5));
            if (valueRange.hasLowerBound()) {
                String lowerStr = valueRange.lowerEndpoint().toString();
                Integer start = Integer.parseInt(lowerStr.substring(0, 4));
                if (start - shardValue > 0) {
                    continue;
                }
            }
            if (valueRange.hasUpperBound()) {
                String upperStr = valueRange.upperEndpoint().toString();
                Integer end = Integer.parseInt(upperStr.substring(0, 4));
                if (end - shardValue < 0) {
                    continue;
                }
            }
            availables.add(target);
        }
        return availables;
    }
}

The init method is called through another class instantiation, and the difficulty is how to get the LogShardingAlgorithm that is instantiated.

import cn.hutool.core.util.ReflectUtil;
import com.google.common.base.Optional;
import com.onegene.platform.system.log.LogShardingAlgorithm;
import org.apache.shardingsphere.core.rule.ShardingRule;
import org.apache.shardingsphere.core.rule.TableRule;
import org.apache.shardingsphere.core.strategy.route.ShardingStrategy;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.ShardingContext;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
/**
 * @author: laoliangliang
 * @description:
 * @create: 2020/1/18 8:29
 **/
@Component
public class StartupConfig {
    @Autowired
    private DataSource dataSource;

    @PostConstruct
    public void init() {
        this.loadLogInit();
    }

    private void loadLogInit() {
        if (dataSource instanceof ShardingDataSource) {
            ShardingDataSource sds = (ShardingDataSource) dataSource;
            ShardingContext shardingContext = sds.getShardingContext();
            ShardingRule shardingRule = shardingContext.getShardingRule();
            Optional<TableRule> systemLog = shardingRule.findTableRule("system_log");
            TableRule tableRule = systemLog.orNull();
            if (tableRule != null) {
                ShardingStrategy tableShardingStrategy = tableRule.getTableShardingStrategy();
                LogShardingAlgorithm preciseShardingAlgorithm = (LogShardingAlgorithm) ReflectUtil.getFieldValue(tableShardingStrategy, "preciseShardingAlgorithm");
                LogShardingAlgorithm rangeShardingAlgorithm = (LogShardingAlgorithm) ReflectUtil.getFieldValue(tableShardingStrategy, "rangeShardingAlgorithm");
                preciseShardingAlgorithm.init();
                rangeShardingAlgorithm.init();
            }
        }
    }
}

1.3. summary

It can be seen from the source code that the object instantiated by LogShardingAlgorithm is put into ShardingDataSource. Then we need to take it out. If it doesn't provide get method normally, we need to use reflection hardware to take it out

From the above code, we can see that range segmentation and precise segmentation need to instantiate two classes. I want to find out if they can be combined into one class. I also found that some versions can realize range and precise segmentation query at the same time by using complexkeys shardingalgorithm. But after my actual test, the current version 4.0.0 is not good, because the following code is Complex fragment source code

public final class ComplexShardingStrategy implements ShardingStrategy {
    
    @Getter
    private final Collection<String> shardingColumns;
    
    private final ComplexKeysShardingAlgorithm shardingAlgorithm;
    
    public ComplexShardingStrategy(final ComplexShardingStrategyConfiguration complexShardingStrategyConfig) {
        Preconditions.checkNotNull(complexShardingStrategyConfig.getShardingColumns(), "Sharding columns cannot be null.");
        Preconditions.checkNotNull(complexShardingStrategyConfig.getShardingAlgorithm(), "Sharding algorithm cannot be null.");
        shardingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        shardingColumns.addAll(Splitter.on(",").trimResults().splitToList(complexShardingStrategyConfig.getShardingColumns()));
        shardingAlgorithm = complexShardingStrategyConfig.getShardingAlgorithm();
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<RouteValue> shardingValues) {
        Map<String, Collection<Comparable<?>>> columnShardingValues = new HashMap<>(shardingValues.size(), 1);
        String logicTableName = "";
        for (RouteValue each : shardingValues) {

            // Key point here is that he forcibly converted the value of each to ListRouteValue, and the range query corresponds to BetweenRouteValue, so it is stuck at the source code level. Unless the policy is rewritten, this cannot be used as before
            columnShardingValues.put(each.getColumnName(), ((ListRouteValue) each).getValues());
            logicTableName = each.getTableName();
        }
        Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, new ComplexKeysShardingValue(logicTableName, columnShardingValues));
        Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        result.addAll(shardingResult);
        return result;
    }
}

Welcome to pay attention to the public address, reply to the "teaching video" and learn progress together.

Posted by nubby on Fri, 17 Jan 2020 22:01:28 -0800