4 стратегии сегментирования для подбазы данных и подтаблицы sharding-jdbc, довольно простые

Java база данных
4 стратегии сегментирования для подбазы данных и подтаблицы sharding-jdbc, довольно простые

над«Быстрый старт Sharding — JDBC Middleware Sharding — JDBC (обязательный курс)»введен вsharding-jdbcОсновная концепцияSQLРазличные операторы, которые появляются в>,<,between and,inд., чтобы выбрать соответствующую стратегию разделения данных.

Прежде чем продолжить, я задам вопросы и ответы. Маленький партнер задал вопрос в частном порядке два дня назад и сказал:

Что, если некоторые из моих таблиц являются подтаблицами базы данных, а другая часть не является подтаблицей базы данных? Как я могу получить к нему доступ в обычном режиме?

Это типичная проблема.Мы знаем, что подтаблицы подбазы данных предназначены для некоторых таблиц, объем данных которых продолжает значительно расти, таких как пользовательские таблицы, таблицы заказов и т. д., а не для сегментирования всех таблиц по всем направлениям. Итак, как разделить несегментированную таблицу и сегментированную таблицу, обычно есть два решения.

  • Строго разделить библиотеку функций, отделить сегментированную библиотеку от не сегментированной библиотеки и переключать доступ к источнику данных по требованию в бизнес-коде.
  • Установите источник данных по умолчанию наSharding-JDBCНапример, если правила сегментирования не установлены для нешардированных таблиц, они не будут выполняться, потому что правила маршрутизации не могут быть найдены.В настоящее время мы устанавливаем источник данных по умолчанию и всегда обращаемся к библиотеке по умолчанию, когда правила не найдены.
# 配置数据源 ds-0
spring.shardingsphere.datasource.ds-0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds-0.driverClassName=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-0.url=jdbc:mysql://47.94.6.5:3306/ds-0?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
spring.shardingsphere.datasource.ds-0.username=root
spring.shardingsphere.datasource.ds-0.password=root

# 默认数据源,未分片的表默认执行库
spring.shardingsphere.sharding.default-data-source-name=ds-0

В этой статье мы попрактикуемся в использовании четырех стратегий сегментирования для конкретных сценариев использования SQL и выполним некоторые приготовления перед началом.

  • Стандартная стратегия разделения

  • Составная стратегия шардинга

  • стратегия сегментирования выражений строк

  • Стратегия разделения подсказок

Готов к работе

Сначала создайте две базы данныхds-0,ds-1, создать таблицы в двух библиотеках соответственноt_order_0,t_order_1,t_order_2,t_order_item_0,t_order_item_1,t_order_item_26 таблиц, давайте посмотрим, как это применить в разных сценарияхsharding-jdbc4 стратегии шардинга.

t_order_nСтруктура таблицы следующая:

CREATE TABLE `t_order_0` (
  `order_id` bigint(200) NOT NULL,
  `order_no` varchar(100) DEFAULT NULL,
  `user_id` bigint(200) NOT NULL,
  `create_name` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

t_order_item_nСтруктура таблицы следующая:

CREATE TABLE `t_order_item_0` (
  `item_id` bigint(100) NOT NULL,
  `order_id` bigint(200) NOT NULL,
  `order_no` varchar(200) NOT NULL,
  `item_name` varchar(50) DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

Стратегия шардинга делится на分表策略а также分库策略, реализуют алгоритм шардинга в принципе одинаково, разница в паре библиотекds-0,ds-1, парный столt_order_0 ··· t_order_nждать обработки.

Стандартная стратегия разделения

сцены, которые будут использоваться: в операторе SQL>,>=, <=,<,=,INа такжеBETWEEN ANDоператор, эта стратегия сегментирования может быть применена.

Стандартная стратегия разделения (StandardShardingStrategy), он поддерживает сегментирование базы данных и таблиц только на основе одного ключа сегмента (поля) и предоставляет два алгоритма сегментирования.PreciseShardingAlgorithm(точный шардинг) иRangeShardingAlgorithm(разделение диапазона).

При использовании стандартной стратегии сегментирования точный алгоритм сегментирования является обязательным алгоритмом для SQL, содержащего=а такжеINсегментация; алгоритм сегментации диапазона является необязательным и используется дляBETWEEN ANDФрагментарная обработка.

Один раз мы не настраиваем алгоритм сегментации диапазона, и снова используется SQLBETWEEN ANDилиlikeи т. д., то SQL будет выполняться один за другим на пути маршрутизации всей базы данных и таблиц, а производительность запросов будет очень низкой, требующей особого внимания.

Следующая пользовательская реализация精准分片算法а также范围分片算法.

1. Точный алгоритм шардинга

1.1 Алгоритм точного разделения базы данных

Методы реализации пользовательских точных алгоритмов секционирования базы данных и таблиц примерно одинаковы, и оба должны быть реализованы.PreciseShardingAlgorithmинтерфейс и переопределитьdoSharding()метод, но конфигурация немного отличается, и это просто пустой метод, мы должны сами разобраться с логикой подбиблиотеки и подтаблицы.То же самое касается и других стратегий шардинга..

SELECT * FROM t_order where  order_id = 1 or order_id in (1,2,3);

Затем мы реализуем точную стратегию секционирования базы данных через состояние разделов.order_idМетод по модулю (как его реализовать — зависит от ваших предпочтений) вычисляет, в какую библиотеку следует роутить SQL, а рассчитанная информация о библиотеке шардинга будет храниться в контексте шардинга, что удобно для использования в последующих таблицах шардинга.

/**
 * @author xiaofu 公众号【程序员内点事】
 * @description 自定义标准分库策略
 * @date 2020/10/30 13:48
 */
public class MyDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {

        /**
         * databaseNames 所有分片库的集合
         * shardingValue 为分片属性,其中 logicTableName 为逻辑表,columnName 分片健(字段),value 为从 SQL 中解析出的分片健的值
         */
        for (String databaseName : databaseNames) {
            String value = shardingValue.getValue() % databaseNames.size() + "";
            if (databaseName.endsWith(value)) {
                return databaseName;
            }
        }
        throw new IllegalArgumentException();
    }
}

вCollection<String>Параметры последовательно используются в нескольких стратегиях сегментирования, а значением является набор всех сегментированных библиотек при сегментировании.databaseNames, который представляет собой набор всех сегментированных таблиц в соответствующей сегментированной библиотеке при сегментировании.tablesNames;PreciseShardingValueявляется атрибутом фрагментации, гдеlogicTableNameлогическая таблица,columnNameключ осколка (поле),valueЗначение ключа сегмента, полученное из SQL.

а такжеapplication.propertiesНужно только изменить имя стратегии подбазы данных в файле конфигурацииdatabase-strategyстандартный режимstandard, алгоритм шардингаstandard.precise-algorithm-class-nameЭто путь к классам настроенного алгоритма точной подбиблиотеки.

### 分库策略
# 分库分片健
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.sharding-column=order_id
# 分库分片算法
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=com.xiaofu.sharding.algorithm.dbAlgorithm.MyDBPreciseShardingAlgorithm

1.2 Алгоритм точного деления таблицы

Также реализован точный алгоритм разбиения таблицыPreciseShardingAlgorithmинтерфейс и переопределитьdoSharding()метод.

/**
 * @author xiaofu 公众号【程序员内点事】
 * @description 自定义标准分表策略
 * @date 2020/10/30 13:48
 */
public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {

        /**
         * tableNames 对应分片库中所有分片表的集合
         * shardingValue 为分片属性,其中 logicTableName 为逻辑表,columnName 分片健(字段),value 为从 SQL 中解析出的分片健的值
         */
        for (String tableName : tableNames) {
            /**
             * 取模算法,分片健 % 表数量
             */
            String value = shardingValue.getValue() % tableNames.size() + "";
            if (tableName.endsWith(value)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException();
    }
}

Когда стол разделенCollection<String>Параметр — рассчитанная выше библиотека шардинга и соответствующий набор всех таблиц шардингаtablesNames;PreciseShardingValueявляется атрибутом фрагментации, гдеlogicTableNameлогическая таблица,columnNameключ осколка (поле),valueЗначение ключа сегмента, полученное из SQL.

application.propertiesВ файле конфигурации также нужно только изменить имя стратегии подтаблицы.database-strategyстандартный режимstandard, алгоритм шардингаstandard.precise-algorithm-class-nameЭто путь к классам настроенного точного алгоритма секционирования таблицы.

# 分表策略
# 分表分片健
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.sharding-column=order_id
# 分表算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.standard.precise-algorithm-class-name=com.xiaofu.sharding.algorithm.tableAlgorithm.MyTablePreciseShardingAlgorithm

В этом нетрудно убедиться, реализация пользовательской подбазы данных и табличных подалгоритмов в основном одинакова, поэтому позже мы продемонстрируем только подбазу данных.

2. Алгоритм фрагментации диапазона

сцены, которые будут использоваться: когда используется поле ключа фрагмента в нашем SQLBETWEEN ANDОператор будет использовать этот алгоритм и будет обрабатывать сегментирование и логику сегментирования в соответствии со значением диапазона значений ключа сегментирования, заданным в SQL.

SELECT * FROM t_order where  order_id BETWEEN 1 AND 100;

Необходимо реализовать собственный алгоритм разделения диапазонаRangeShardingAlgorithmинтерфейс, переопределениеdoSharding()метод, ниже я рассчитываю логику каждой подбиблиотеки и подтаблицы, проходя интервал ключ-значение осколка.

/**
 * @author xinzhifu
 * @description 范围分库算法
 * @date 2020/11/2 12:06
 */
public class MyDBRangeShardingAlgorithm implements RangeShardingAlgorithm<Integer> {

    @Override
    public Collection<String> doSharding(Collection<String> databaseNames, RangeShardingValue<Integer> rangeShardingValue) {

        Set<String> result = new LinkedHashSet<>();
        // between and 的起始值
        int lower = rangeShardingValue.getValueRange().lowerEndpoint();
        int upper = rangeShardingValue.getValueRange().upperEndpoint();
        // 循环范围计算分库逻辑
        for (int i = lower; i <= upper; i++) {
            for (String databaseName : databaseNames) {
                if (databaseName.endsWith(i % databaseNames.size() + "")) {
                    result.add(databaseName);
                }
            }
        }
        return result;
    }
}

то же, что и вышеCollection<String> При сегментировании базы данных и таблицы он представляет собой имя сегментированной базы данных и набор имен таблиц соответственно.RangeShardingValue Здесь метод значения немного отличается,lowerEndpoint представляет начальное значение,upperEndpoint представляет собой пороговое значение.

С точки зрения конфигурации, поскольку алгоритм сегментирования диапазона и алгоритм точного сегментирования используются в рамках стандартной стратегии сегментирования, вам нужно только добавитьrange-algorithm-class-name Вы можете настроить путь к классам алгоритма разделения диапазона.

# 精准分片算法
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.precise-algorithm-class-name=com.xiaofu.sharding.algorithm.dbAlgorithm.MyDBPreciseShardingAlgorithm
# 范围分片算法
spring.shardingsphere.sharding.tables.t_order.database-strategy.standard.range-algorithm-class-name=com.xiaofu.sharding.algorithm.dbAlgorithm.MyDBRangeShardingAlgorithm

Составная стратегия шардинга

сцены, которые будут использоваться: в операторе SQL>,>=, <=,<,=,INа такжеBETWEEN ANDи другие операторы, разница в том, что составная стратегия сегментирования поддерживает операции с несколькими ключами сегментов.

Далее реализуем одновременныйorder_id,user_idДва поля используются в качестве ключей сегментирования для настройки составной стратегии сегментирования.

 SELECT * FROM t_order where  user_id =0  and order_id = 1;

Давайте сначала изменим исходную конфигурацию.complex.sharding-columnпереключиться наcomplex.sharding-columns множественное число, добавить один к ключу осколкаuser_id, название стратегии сегментирования изменено наcomplex,complex.algorithm-class-nameЗаменено нашим собственным составным алгоритмом сегментирования.

### 分库策略
# order_id,user_id 同时作为分库分片健
spring.shardingsphere.sharding.tables.t_order.database-strategy.complex.sharding-column=order_id,user_id
# 复合分片算法
spring.shardingsphere.sharding.tables.t_order.database-strategy.complex.algorithm-class-name=com.xiaofu.sharding.algorithm.dbAlgorithm.MyDBComplexKeysShardingAlgorithm

Индивидуальная стратегия составного сегментирования, которая будет реализованаComplexKeysShardingAlgorithmинтерфейс, повторноdoSharding()метод.

/**
 * @author xiaofu 公众号【程序员内点事】
 * @description 自定义复合分库策略
 * @date 2020/10/30 13:48
 */
public class MyDBComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Integer> {


    @Override
    public Collection<String> doSharding(Collection<String> databaseNames, ComplexKeysShardingValue<Integer> complexKeysShardingValue) {

        // 得到每个分片健对应的值
        Collection<Integer> orderIdValues = this.getShardingValue(complexKeysShardingValue, "order_id");
        Collection<Integer> userIdValues = this.getShardingValue(complexKeysShardingValue, "user_id");

        List<String> shardingSuffix = new ArrayList<>();
        // 对两个分片健同时取模的方式分库
        for (Integer userId : userIdValues) {
            for (Integer orderId : orderIdValues) {
                String suffix = userId % 2 + "_" + orderId % 2;
                for (String databaseName : databaseNames) {
                    if (databaseName.endsWith(suffix)) {
                        shardingSuffix.add(databaseName);
                    }
                }
            }
        }
        return shardingSuffix;
    }

    private Collection<Integer> getShardingValue(ComplexKeysShardingValue<Integer> shardingValues, final String key) {
        Collection<Integer> valueSet = new ArrayList<>();
        Map<String, Collection<Integer>> columnNameAndShardingValuesMap = shardingValues.getColumnNameAndShardingValuesMap();
        if (columnNameAndShardingValuesMap.containsKey(key)) {
            valueSet.addAll(columnNameAndShardingValuesMap.get(key));
        }
        return valueSet;
    }
}

Collection<String>Использование остается прежним из-за поддержки здоровья нескольких осколков.ComplexKeysShardingValueИспользовать ключ сегмента в качестве атрибута сегментаkey, значение ключа сегментаvalueизmapдля хранения свойств ключа сегмента.

стратегия сегментирования выражений строк

стратегия разделения выражения строки (InlineShardingStrategy), использовать в конфигурацииGroovyвыражение, обеспечивающее доступ к=а такжеINподдержка операций сегментирования, он поддерживает только один ключ сегмента.

Стратегия сегментации строкового выражения подходит для простых алгоритмов сегментации без специальных алгоритмов сегментации, что избавляет от утомительной разработки кода и является самой простой из нескольких стратегий сегментации.

Его конфигурация довольно лаконична, эта стратегия сегментирования используетinline.algorithm-expressionНапишите выражения.

Например:ds-$->{order_id % 2}выражать правоorder_idВыполните расчет по модулю,$Это подстановочный знак, используемый для принятия результата по модулю и, наконец, для вычисления подбиблиотеки.ds-0 ··· ds-n, что в целом относительно просто.

# 行表达式分片键
sharding.jdbc.config.sharding.tables.t_order.database-strategy.inline.sharding-column=order_id
# 表达式算法
sharding.jdbc.config.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds-$->{order_id % 2}

Стратегия разделения подсказок

Стратегия разделения подсказок (HintShardingStrategy) немного отличается от приведенных выше стратегий сегментирования.Эта стратегия сегментирования не требует настройки ключей сегментов, и значения ключей сегментов больше не анализируются из SQL.Вместо этого информация о сегментах указывается извне, так что SQL может указать Executed в подбиблиотеках и подтаблицах.ShardingSphereпройти черезHintAPI реализует указанную операцию, которая фактически является правилом шардинга.tablerule,databaseruleОт централизованной конфигурации к индивидуальной конфигурации.

Например, если мы хотим, чтобы таблица заказовt_orderиспользоватьuser_idИспользуйте ключ сегментирования для сегментирования базы данных и таблицы, ноt_orderнет в таблицеuser_idВ этом поле ключ сегмента или библиотеку сегментов можно вручную указать извне через Hint API.

Ниже мы приведем SQL без условия фрагментации, чтобы увидеть, как указать ключ фрагментации, чтобы направить его в указанную библиотечную таблицу.

SELECT * FROM t_order;

Использование стратегии сегментирования подсказки также необходимо настроить и внедрить.HintShardingAlgorithmинтерфейс и переопределениеdoSharding()метод.

/**
 * @author xinzhifu
 * @description hit分表算法
 * @date 2020/11/2 12:06
 */
public class MyTableHintShardingAlgorithm implements HintShardingAlgorithm<String> {

    @Override
    public Collection<String> doSharding(Collection<String> tableNames, HintShardingValue<String> hintShardingValue) {

        Collection<String> result = new ArrayList<>();
        for (String tableName : tableNames) {
            for (String shardingValue : hintShardingValue.getValues()) {
                if (tableName.endsWith(String.valueOf(Long.valueOf(shardingValue) % tableNames.size()))) {
                    result.add(tableName);
                }
            }
        }
        return result;
    }
}

После настройки алгоритма реализуется только его часть, и его нужно передать перед вызовом SQL.HintManagerУкажите информацию о подбиблиотеке и подтаблице. Поскольку каждое добавляемое правило помещается вThreadLocalвнутри, поэтому сначала выполнитеclear()Очистите последнее правило, иначе будет сообщено об ошибке;addDatabaseShardingValueУстановите ключевое значение ключа сегмента базы данных,addTableShardingValueЗадайте значение ключа сегмента таблицы сегментов.setMasterRouteOnlyРазделение чтения и записи заставляет главную библиотеку чтения избегать задержек, вызванных репликацией ведущий-ведомый.

// 清除掉上一次的规则,否则会报错
HintManager.clear();
// HintManager API 工具类实例
HintManager hintManager = HintManager.getInstance();
// 直接指定对应具体的数据库
hintManager.addDatabaseShardingValue("ds",0);
// 设置表的分片健
hintManager.addTableShardingValue("t_order" , 0);
hintManager.addTableShardingValue("t_order" , 1);
hintManager.addTableShardingValue("t_order" , 2);

// 在读写分离数据库中,Hint 可以强制读主库
hintManager.setMasterRouteOnly();

отладка отладки видит, что у нас естьt_orderТаблица задает значение ключа сегментирования таблицы сегментирования, которое можно использовать в пользовательском алгоритме.HintShardingValueпараметры успешно получены.

propertiesНет необходимости указывать ключ сегментирования в конфигурации в файле, достаточно пути к классу пользовательского алгоритма сегментирования Hint.

# Hint分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.hint.algorithm-class-name=com.xiaofu.sharding.algorithm.tableAlgorithm.MyTableHintShardingAlgorithm

Далее функции Sharding-JDBC будут реализованы одна за другой, такие как распределенные транзакции, управление услугами и т. д. В следующей статье мы рассмотрим «Как настроить распределенные самовозрастающие идентификаторы первичных ключей для подбаз данных и Подтаблицы».

Адрес кейса на GitHub:GitHub.com/Программист-NDS…

Разобраны и розданы друзьям сотни различных технических электронных книг. Подпишитесь на официальный аккаунт, чтобы ответить【666] Самовывоз. Мы создали группу технического обмена с друзьями, чтобы обсуждать технологии и делиться технической информацией, стремясь вместе учиться и развиваться. Если вам интересно, присоединяйтесь к нам!