Одна статья Quick Start Sharding-JDBC Middleware Sharding-JDBC (обязательный курс)

Java
Одна статья Quick Start Sharding-JDBC Middleware Sharding-JDBC (обязательный курс)

книга сверху«Подтаблица подтаблицы базы данных для быстрого запуска одной статьи (обязательный курс)»,Эта статья длилась долго.Изначально ее планировалось закончить неделю назад.В итоге внутри семьи произошла внезапная кадровая перестановка,и руководство передало власть,а потом объявило,что я официально отец, а потом семейный статус упал на третье Имя, и на меня возложили долгосрочную задачу по уходу: заботиться о ребенке. Взгляните на наши красивые фотографии, стандартная маленькая леди симпатичная.

千金小姐姐

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

1. Введение в Sharding-JDBC

Sharding-JDBC Это была структура подбазы данных и подтаблиц, используемая внутри Dangdang.com. Исходный код был открыт для внешнего мира только в 2017 году. улучшена, и теперь она была переименована.ShardingSphere, 16 апреля 2020 года официально сталоApacheПроект высшего уровня Software Foundation.

С постоянной сменой версийShardingSphereОсновные функции также стали диверсифицированными. С самого начала версия SHARDING-JDBC 1.0 имела только Sharding Data Charding, чтобы Sharding-JDBC 2.0 версию начала поддерживать управление базы данных (Центр реестра, Центр конфигурации и т. Д.), А затем для версии Sharding-JDBC 3.0 добавлена ​​распределенная транзакция (поддержка заAtomikos,Narayana,Bitronix,Seata), который теперь был преобразован в Sharding-JDBC 4.0.

在这里插入图片描述

Нынешняя ShardingSphere относится не только к определенному фреймворку, но и к экосистеме, этой экосистеме.Sharding-JDBC,Sharding-ProxyиSharding-SidecarПредставлены три решения промежуточного программного обеспечения для распределенных баз данных с открытым исходным кодом.

ShardingSphereпредшественник былSharding-JDBC, так что это самый классический и зрелый компонент во всей структуре.Начнем сSharding-JDBCФреймворк начинается с изучения подбазы данных и подтаблицы.

2. Основные концепции

В началеSharding-JDBCПрежде чем подбаза данных и подтаблицы будут реализованы на практике, нам необходимо понять некоторые основные концепции подбазы данных и подтаблиц.

Фрагментация

Как правило, когда мы говорим о подбазе данных и подтаблице, большинство из них основаны на режиме горизонтальной сегментации (горизонтальная подбаза данных, подтаблица).t_orderРазделить для создания нескольких небольших таблиц данных с полностью согласованной структурой таблиц.t_order_0,t_order_1,  t_order_n, каждая таблица сохраняет только часть данных исходной большой таблицы при выполненииSQLпройдет分库策略,分片策略Данные в разные базы данных, таблицы.

在这里插入图片描述

узел данных

Узел данных — это неделимая наименьшая единица данных (таблица) в подбазе данных и подтаблице, которая состоит из имени источника данных и таблицы данных, например, на рисунке выше.order_db_1.t_order_0,order_db_2.t_order_1представляет узел данных.

логическая таблица

Логическая таблица — это общий термин для группы таблиц с одинаковой логикой и структурой данных. Например, ставим форму заказаt_orderРазделить наt_order_0 ··· t_order_9等 10张表。 На этом этапе мы обнаружим, что в базе данных больше нет базы данных после подбазы данных и подтаблицы.t_orderЭта таблица вместоt_order_n, но мы пишем в кодеSQLвсе еще нажмитеt_orderнаписать. В настоящее времяt_orderЭто эти разделенные столы逻辑表.

реальный стол

Настоящая таблица указана вышеt_order_nФизические таблицы, реально существующие в базе данных.

осколочный ключ

Поля базы данных для шардинга. мы будемt_orderПосле фрагментации таблицы при выполнении SQLorder_idМетод по модулю используется для определения того, в какой таблице, в какой базе данных должны выполняться эти данные.order_idполеt_orderСостояние шардинга таблицы.

在这里插入图片描述

Таким образом, связанные данные одного и того же порядка будут храниться в одной и той же таблице базы данных, что значительно повышает производительность поиска данных, не толькоsharding-jdbcОн также поддерживает сегментирование на основе нескольких полей в качестве ключей сегментов.

Алгоритм фрагментации

Выше мы упоминали, что обычный шардинг может быть по модулю ключа шардинга, но это относительно простой вариант, и в реальной разработке мы также надеемся использовать>=,<=,>,<,BETWEENиINЕсли в качестве правил сегментирования для настройки логики сегментирования используются другие условия, необходимо использовать стратегию сегментирования и алгоритм сегментирования.

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

Давайте сначала посмотрим на отношения между ними. Стратегия сегментирования — это просто абстрактное понятие. Она состоит из алгоритма сегментирования и ключа сегментирования. Алгоритм сегментирования выполняет конкретную логику сегментирования данных.

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

分片算法和分片策略的关系

Уведомление: sharding-jdbc напрямую не обеспечивает реализацию алгоритма шардинга, и разработчикам необходимо реализовать его в соответствии со своим бизнесом.

sharding-jdbcОбеспечивает 4 нарезанную арифметику:

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

Алгоритм точного сегментирования (PreciseShardingAlgorithm) используется для одного поля в качестве ключа сегментирования в SQL.=иINДля сегментирования с другими условиями стандартная стратегия сегментирования (StandardShardingStrategy) использовать.

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

Алгоритм сегментирования диапазона (RangeShardingAlgorithm) используется для одного поля в качестве ключа сегментирования в SQL.BETWEEN AND,>,<,>=,<=Для сегментирования с другими условиями стандартная стратегия сегментирования (StandardShardingStrategy) использовать.

3. Составной алгоритм шардинга

Алгоритм комплексного шардирования (ComplexKeysShardingAlgorithm) используется для операций шардирования, где несколько полей используются в качестве ключей шардирования, и одновременно получаются значения нескольких ключей шардирования, а бизнес-логика обрабатывается в соответствии с несколькими полями. Требуется составная стратегия сегментирования (ComplexShardingStrategy) использовать.

4. Алгоритм разделения подсказки

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

Стратегия шардинга

Говоря об алгоритме сегментирования выше, было сказано, что стратегия сегментирования является абстрактной концепцией, а фактическая операция сегментирования завершается алгоритмом сегментирования и ключом сегментирования.

1. Стандартная стратегия шардинга

Стандартная стратегия сегментирования применяется к одному ключу сегмента, эта стратегия поддерживаетPreciseShardingAlgorithmиRangeShardingAlgorithmДва алгоритма шардинга.

вPreciseShardingAlgorithmтребуется для обработки=иINосколок.RangeShardingAlgorithmопционально, для обработкиBETWEEN AND,>,<,>=,<=Условный шардинг, если он не настроенRangeShardingAlgorithm, условия в SQL будут обрабатываться по всему маршруту библиотеки.

2. Стратегия составного сегментирования

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

3. Стратегия фрагментации выражения строки

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

t_order_$->{t_order_id % 4}представлятьt_orderего полеt_order_idВозьмите модуль и разделите его на 4 таблицы, а имена таблицt_order_0прибытьt_order_3.

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

Стратегия сегментирования подсказки, соответствующая приведенному выше алгоритму сегментирования подсказки, путем указания ключа сегмента вместо fromSQLСтратегия шардирования путем извлечения ключей шардов.

Распределенный первичный ключ

После разделения данных очень сложно сгенерировать глобально уникальный первичный ключ для разных узлов данных.Одна и та же логическая таблица (t_order) в разных реальных таблицах (t_order_n) между ключами автоинкремента, потому что они не могут воспринимать друг друга, что приводит к дублированию первичных ключей.

Хотя можно установить автоинкрементный первичный ключ初始值и步⻓Способ избежать конфликта идентификаторов, но это увеличит стоимость обслуживания, отсутствие целостности и масштабируемости. Если вам нужно увеличить количество таблиц сегментирования позже, вам нужно изменить размер шага таблиц сегментирования одну за другой, а стоимость эксплуатации и обслуживания очень высока, поэтому этот метод не рекомендуется.

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

Чтобы упростить начало работы, Apache ShardingSphere имеет встроенныйUUID,SNOWFLAKEДва распределенных генератора первичных ключей, по умолчанию использующих алгоритм Snowflake (snowflake) для создания 64-битных целочисленных данных. Мало того, он также извлекает интерфейс распределенного генератора первичных ключей, что нам удобно для реализации собственного алгоритма генерации первичных ключей с автоинкрементом.

широковещательный стол

Широковещательная таблица: таблица, существующая во всех сегментированных источниках данных. Структура таблицы и данные в таблице абсолютно одинаковы во всех базах данных. Обычно это таблица-словарь или таблица конфигурации.t_config, как только таблица настроена как широковещательная таблица, пока изменяется широковещательная таблица базы данных, данные широковещательной таблицы во всех источниках данных будут синхронизированы.

обязательный стол

Таблица привязки: те основные и подтаблицы, правила сегментирования которых совпадают. Например:t_orderбланк заказа иt_order_itemСписок позиций заказа услуг, все в соответствии сorder_idПоля фрагментированы, поэтому две таблицы связаны друг с другом.

Каково значение существования таблицы привязки?

Обычно используется в нашем бизнесеt_orderиt_order_itemСовместный запрос нескольких таблиц выполняется для других таблиц, но эти таблицы разбиты на N нескольких подтаблиц после подбазы данных и подтаблицы. Если отношение таблицы привязки не настроено, появится декартовский запрос ассоциации продукта, и будут сгенерированы следующие четыре элемента.SQL.

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id 

笛卡尔积查询

Когда связанный запрос выполняется после настройки отношения таблицы привязки, если данные, сгенерированные соответствующими правилами сегментирования таблицы, непротиворечивы, они попадут в одну и ту же базу данных.t_order_0иt_order_item_0Таблицы могут быть связаны.

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id 

绑定表关系

Уведомление: во время связанного запросаt_orderОн действует как основная таблица для всего запроса на объединение. Все соответствующие расчеты маршрутизации используют только стратегию главной таблицы,t_order_itemТакже используются расчеты, связанные с шардингом таблиц.t_orderусловия, поэтому убедитесь, что ключи осколков между таблицами привязки точно такие же.

3. Трюки с JDBC

Нетрудно догадаться по названию,Sharding-JDBCиJDBCУ него много работы, мы знаем, что JDBC — этоJavaСпецификация реляционной базы данных с языковым доступом предназначена для предоставления набора унифицированных стандартов для различных баз данных.Различные производители соблюдают этот стандарт и предоставляют свои собственные решения для реализации вызовов приложений.

在这里插入图片描述

Но на самом деле для разработчиков нас волнует только то, как вызывать JDBC API для доступа к базе данных, главное, чтобы он использовался корректно.DataSource,Connection,Statement,ResultSetДождавшись интерфейса API, вы можете напрямую работать с базой данных. Поэтому, если вы хотите реализовать шардинг данных на уровне JDBC, вы должны расширить функции существующего API.Основываясь на этой идее, Sharding-JDBC переписывает спецификацию JDBC и полностью совместим со спецификацией JDBC.

JDBC流程

к оригиналуDataSource,ConnectionИнтерфейс расширен доShardingDataSource,ShardingConnection, а интерфейс операции сегментирования, доступный для внешнего мира, точно такой же, как интерфейс, представленный в спецификации JDBC.Если вы знакомы с JDBC, вы можете легко применить Sharding-JDBC для реализации сегментирования и сегментирования.

在这里插入图片描述

Так что это работает для любогоJDBCизORMкадр, например:JPA,Hibernate,Mybatis,Spring JDBC TemplateИли используйте JDBC напрямую. Идеально совместим с любым сторонним пулом соединений с базой данных, например:DBCP,C3P0,BoneCP,Druid,HikariCPПоддерживаются почти все основные реляционные базы данных.

ТотSharding-JDBCКак расширить эти интерфейсы?? Если вы хотите узнать ответ, мы начнем с исходного кода, а затем воспользуемся JDBC API вDataSourceВозьмите пример, чтобы увидеть, как его можно переписать и расширить.

источник данныхDataSourceОсновной функцией интерфейса является получение объекта подключения к базе данных.Connection, мы видим, что он предоставляет два метода для внутреннего подключения к базе данных и наследуетCommonDataSourceиWrapperдва интерфейса.


public interface DataSource  extends CommonDataSource, Wrapper {

  /**
   * <p>Attempts to establish a connection with the data source that
   * this {@code DataSource} object represents.
   * @return  a connection to the data source
   */
  Connection getConnection() throws SQLException;

  /**
   * <p>Attempts to establish a connection with the data source that
   * this {@code DataSource} object represents.
   * @param username the database user on whose behalf the connection is
   *  being made
   * @param password the user's password
   */
  Connection getConnection(String username, String password)
    throws SQLException;
}

вCommonDataSourceявляется корневым интерфейсом, который определяет хорошо понятный источник данных, в то время какWrapperИнтерфейс является ключом к расширению функции сегментирования JDBC.

Из-за разных поставщиков баз данных каждый из них может предоставлять некоторые расширенные функции, выходящие за рамки стандартного JDBC API, но эти функции не могут быть напрямую использованы стандартами, отличными от JDBC, иWrapperРоль интерфейса заключается в переносе стандартного интерфейса, отличного от JDBC, предоставленного сторонним поставщиком, в стандартный интерфейс, т. е.适配器模式.

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

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

Например, для прослушивания музыки в наушниках у меня круглая головка наушников, но разъем для мобильного телефона плоский. Если я хочу использовать наушники для прослушивания музыки, я должен использовать адаптер. Этот адаптер играет адаптивную роль. Возьмите каштан: если мыTargetв интерфейсеhello()иword()два метода.

public interface Target {

    void hello();

    void world();
}

Может повторяться из-за версии интерфейсаTargetинтерфейсword()методы могут быть устаревшими или не поддерживаться,AdapteeКатегорияgreet()метод заменитhello()метод.

public class Adaptee {

    public void greet(){

    }
    public void world(){

    }
}

Но в это время еще много старых версийword()используется, лучший способ решить эту проблему — создать адаптерAdapter, значит подходитTargetкласс, который решает проблему совместимости, вызванную обновлением интерфейса.

public class Adapter extends Adaptee implements Target {

    @Override
    public void world() {
        
    }

    @Override
    public void hello() {
        super.greet();
    }

    @Override
    public void greet() {
        
    }
}

иSharding-JDBCОн предоставляет нестандартный интерфейс JDBC, поэтому он также предоставляет аналогичную схему реализации и используетWrapperИнтерфейс используется для адаптации функции фрагментации данных. Помимо DataSource, этот интерфейс наследуют основные объекты, такие как Connection, Statement и ResultSet.

Мы приняли следующиеShardingDataSourceВ исходном коде класса кратко рассматривается процесс реализации.На следующем рисунке показана блок-схема отношений наследования.

ShardingDataSource实现流程

ShardingDataSourceкласс это в оригиналеDataSourceНа основе расширения функции фрагментированная оболочка маршрутизации SQL, контекст перезаписи SQL и механизм обработки набора результатов регистрируются во время инициализации, а также проверяется тип источника данных, поскольку он поддерживает несколько различных типов источников данных одновременно. . Кажется, я не вижу, как сюда вписаться, так что давайте посмотрим вверх.ShardingDataSource унаследованный классAbstractDataSourceAdapter .

@Getter
public class ShardingDataSource extends AbstractDataSourceAdapter {
    
    private final ShardingRuntimeContext runtimeContext;

    /**
     * 注册路由、SQl重写上下文、结果集处理引擎
     */
    static {
        NewInstanceServiceLoader.register(RouteDecorator.class);
        NewInstanceServiceLoader.register(SQLRewriteContextDecorator.class);
        NewInstanceServiceLoader.register(ResultProcessEngine.class);
    }

    /**
     * 初始化时校验数据源类型 并根据数据源 map、分片规则、数据库类型得到一个分片上下文,用来获取数据库连接
     */
    public ShardingDataSource(final Map<String, DataSource> dataSourceMap, final ShardingRule shardingRule, final Properties props) throws SQLException {
        super(dataSourceMap);
        checkDataSourceType(dataSourceMap);
        runtimeContext = new ShardingRuntimeContext(dataSourceMap, shardingRule, props, getDatabaseType());
    }

    private void checkDataSourceType(final Map<String, DataSource> dataSourceMap) {
        for (DataSource each : dataSourceMap.values()) {
            Preconditions.checkArgument(!(each instanceof MasterSlaveDataSource), "Initialized data sources can not be master-slave data sources.");
        }
    }

    /**
     * 数据库连接
     */
    @Override
    public final ShardingConnection getConnection() {
        return new ShardingConnection(getDataSourceMap(), runtimeContext, TransactionTypeHolder.get());
    }
}

AbstractDataSourceAdapter Абстрактный класс в основном получает объекты подключения к базе данных, соответствующие разным типам источников данных.AutoCloseable Интерфейсы для этих ресурсов могут автоматически отключаться после использования ресурсов (вызовclose метод), затем посмотрите на унаследованный классAbstractUnsupportedOperationDataSource.

@Getter
public abstract class AbstractDataSourceAdapter extends AbstractUnsupportedOperationDataSource implements AutoCloseable {
    
    private final Map<String, DataSource> dataSourceMap;
    
    private final DatabaseType databaseType;
    
    public AbstractDataSourceAdapter(final Map<String, DataSource> dataSourceMap) throws SQLException {
        this.dataSourceMap = dataSourceMap;
        databaseType = createDatabaseType();
    }
    
    public AbstractDataSourceAdapter(final DataSource dataSource) throws SQLException {
        dataSourceMap = new HashMap<>(1, 1);
        dataSourceMap.put("unique", dataSource);
        databaseType = createDatabaseType();
    }
    
    private DatabaseType createDatabaseType() throws SQLException {
        DatabaseType result = null;
        for (DataSource each : dataSourceMap.values()) {
            DatabaseType databaseType = createDatabaseType(each);
            Preconditions.checkState(null == result || result == databaseType, String.format("Database type inconsistent with '%s' and '%s'", result, databaseType));
            result = databaseType;
        }
        return result;
    }
    
    /**
     * 不同数据源类型获取数据库连接
     */
    private DatabaseType createDatabaseType(final DataSource dataSource) throws SQLException {
        if (dataSource instanceof AbstractDataSourceAdapter) {
            return ((AbstractDataSourceAdapter) dataSource).databaseType;
        }
        try (Connection connection = dataSource.getConnection()) {
            return DatabaseTypes.getDatabaseTypeByURL(connection.getMetaData().getURL());
        }
    }
    
    @Override
    public final Connection getConnection(final String username, final String password) throws SQLException {
        return getConnection();
    }
    
    @Override
    public final void close() throws Exception {
        close(dataSourceMap.keySet());
    }
}

AbstractUnsupportedOperationDataSourceвыполнитьDataSourceинтерфейс и унаследованноеWrapperAdapterВнутри класса нет определенного метода, который действует только как мост, но он немного похож на пример шаблона адаптера, о котором мы говорили ранее.

public abstract class AbstractUnsupportedOperationDataSource extends WrapperAdapter implements DataSource {
    
    @Override
    public final int getLoginTimeout() throws SQLException {
        throw new SQLFeatureNotSupportedException("unsupported getLoginTimeout()");
    }
    
    @Override
    public final void setLoginTimeout(final int seconds) throws SQLException {
        throw new SQLFeatureNotSupportedException("unsupported setLoginTimeout(int seconds)");
    }
}

WrapperAdapterпредставляет собой класс адаптера-оболочки, который реализуетWrapperинтерфейс, который имеет два основных методаrecordMethodInvocationДля добавления методов и параметров для выполнения, иreplayMethodsInvocationЗатем добавленные методы и параметры выполняются посредством отражения. Если присмотреться, то можно увидеть, что используются оба метода.JdbcMethodInvocationсвоего рода.

public abstract class WrapperAdapter implements Wrapper {
    
    private final Collection<JdbcMethodInvocation> jdbcMethodInvocations = new ArrayList<>();
 
    /**
     * 添加要执行的方法
     */
    @SneakyThrows
    public final void recordMethodInvocation(final Class<?> targetClass, final String methodName, final Class<?>[] argumentTypes, final Object[] arguments) {
        jdbcMethodInvocations.add(new JdbcMethodInvocation(targetClass.getMethod(methodName, argumentTypes), arguments));
    }
    
    /**
     * 通过反射执行 上边添加的方法
     */
    public final void replayMethodsInvocation(final Object target) {
        for (JdbcMethodInvocation each : jdbcMethodInvocations) {
            each.invoke(target);
        }
    }
}

JdbcMethodInvocationКласс в основном применяет отражение через входящиеmethodМетоды иargumentsПараметр выполняет соответствующий метод, поэтому методы, отличные от JDBC, можно вызывать через API JDBC.

@RequiredArgsConstructor
public class JdbcMethodInvocation {
    
    @Getter
    private final Method method;
    
    @Getter
    private final Object[] arguments;
    
    /**
     * Invoke JDBC method.
     * 
     * @param target target object
     */
    @SneakyThrows
    public void invoke(final Object target) {
        method.invoke(target, arguments);
    }
}

ТотSharding-JDBCПосле расширения интерфейса JDBC API, что вы сделали в новой функции сегментирования?

Таблица делится на несколько подтаблиц после подбазы данных и подтаблицы и распределяется по разным базам данных.Без изменения исходного бизнес-SQL,Sharding-JDBCДля правильного выполнения необходимо внести некоторые изменения в SQL.

Грубый процесс выполнения:SQL 解析 -> 执⾏器优化 -> SQL 路由 -> SQL 改写 -> SQL 执⾏ -> 结果归并Он состоит из шести шагов, и давайте посмотрим, что делает каждый шаг вместе.

在这里插入图片描述

Разбор SQL

Процесс синтаксического анализа SQL разделен на два этапа: лексический анализ и синтаксический анализ.Например, в следующем SQL-запросе для пользовательских заказов лексический анализ используется для дизассемблирования SQL на неделимые атомарные единицы. Согласно словарю, предоставленному различными диалектами базы данных, эти единицы классифицируются по типам, таким как ключевые слова, выражения, переменные или операторы.

SELECT order_no,price FROM t_order_ where user_id = 10086 and order_status > 0

Затем синтаксический анализ преобразует разделенный SQL в абстрактное синтаксическое дерево и, проходя по абстрактному синтаксическому дереву, извлекает контекст, необходимый для фрагментации, а контекст содержит информацию о поле запроса (Field), табличная информация (Table),условия запроса(Condition), сортировка информации (Order By), группировка информации (Group By) и информацию о разбивке на страницы (Limit) и т. д., и отметьте позиции в SQL, которые, возможно, потребуется переписать.

抽象语法树

Оптимизация исполнителя

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

SQL-маршрутизация

Маршрутизация SQL анализирует контекст сегментирования, сопоставляет политику сегментирования, настроенную пользователем, и создает путь маршрутизации. Простое понимание заключается в том, что мы можем рассчитать, в какой таблице и в какой базе данных должен выполняться SQL в соответствии с настроенной нами стратегией сегментирования, а маршрутизацию SQL можно различать в зависимости от того, есть ли ключ сегмента или нет.分片路由и广播路由.

官方路由图谱

Маршруты с ключами сегментов называются маршрутами сегментов и подразделяются на три типа: прямые маршруты, стандартные маршруты и маршруты декартовых произведений.

Стандартная маршрутизация

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

Когда оператор ключа SQL Shard=результат маршрутизации попадет в одну библиотеку (таблицу), когда оператор разделения BETWEENили INКогда диапазон равен, результаты маршрутизации не обязательно попадают в уникальную базу данных (таблицу), поэтому логический SQL может в конечном итоге быть разделен на несколько реальных SQL для выполнения.

SELECT * FROM t_order  where t_order_id in (1,2)

После обработки маршрутизации SQL

SELECT * FROM t_order_0  where t_order_id in (1,2)
SELECT * FROM t_order_1  where t_order_id in (1,2)

прямой маршрут

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

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

Декартова маршрутизация продукта

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


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

Полная маршрутизация таблиц базы данных

Вся маршрутизация таблиц базы данных предназначена для базы данных.DQL иDML,а такжеDDLи так далее, когда мы выполняем логическую таблицуt_orderКогда SQL, соответствующая реальная таблица во всех сегментированных библиотекахt_order_0 ··· t_order_nВыполнять по одному.

Полная библиотечная маршрутизация

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

Настроить библиотекуautocommitПосле установки атрибута команда выполняется во всех соответствующих реальных библиотеках.

SET autocommit=0;

полная маршрутизация экземпляра

Полная маршрутизация экземпляра — это операция DCL для экземпляров базы данных (установка или изменение разрешений пользователя или роли базы данных), например: создание заказа пользователя, эта команда будет выполняться во всех реальных экземплярах базы данных, чтобы гарантировать, что пользователь заказа может нормально получить доступ к каждой базе данных. пример.

CREATE USER order@127.0.0.1 identified BY '程序员内点事';

Одноадресная маршрутизация

Одноадресная маршрутизация используется для получения реальной информации о таблице, такой как получение информации описания таблицы:

DESCRIBE t_order; 

t_orderНастоящая таблицаt_order_0 ···· t_order_n, их структура описания точно такая же, нам нужно только один раз выполнить его на любой реальной таблице.

блокировать маршрутизацию

Используется для защиты операций SQL в базе данных, например:

USE order_db;

Эта команда не будет выполняться в реальной базе данных, потому чтоShardingSphereИспользуется логическая схема (организация и структура базы данных), поэтому нет необходимости посылать команду на переключение базы данных в реальную базу данных.

SQL переписать

Перепишите SQL, разработанный на основе логических таблиц, в операторы, которые могут быть правильно выполнены в реальной базе данных. например, запросt_orderТаблица заказов, в нашей фактической разработке SQL основан на логической таблицеt_orderнаписано.

SELECT * FROM t_order

Но в реальной базе после ветки забиваютt_orderТаблица больше не существует, но разделена на несколько подтаблицt_order_nВыполнение по исходному SQL явно нецелесообразно, если он разбросан по разным базам, в этом случае необходимо переписать имя логической таблицы в конфигурации подтаблицы на реальное имя таблицы, полученное после маршрутизации.

SELECT * FROM t_order_n

выполнение SQL

Безопасно и эффективно отправляйте перенаправленный и переписанный реальный SQL в базовый источник данных для выполнения. Но этот процесс предназначен не только для отправки SQL непосредственно в источник данных для выполнения через JDBC, но и для балансировки потребления создания соединения с источником данных и использования памяти, и он автоматически сбалансирует контроль ресурсов и эффективность выполнения.

Объединить результаты

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

4. Быстрая практика

Ниже мы объединяемSpringboot + mybatisplusБыстро создайте случай подбазы данных и подтаблицы.

1. Подготовка

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

创建分片库表Структура таблицы следующая:

t_order_0форма заказа

CREATE TABLE `t_order_0` (
  `order_id` bigint(200) NOT NULL,
  `order_no` varchar(100) DEFAULT 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_0иt_order_item_0взаимосвязанная таблица

CREATE TABLE `t_order_item_0` (
  `item_id` bigint(100) 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;


широковещательный столt_config

  `id` bigint(30) NOT NULL,
  `remark` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `last_modify_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ShardingSphereПредусмотрено четыре метода настройки шарда:

  • Конфигурация кода Java

  • Yaml, конфигурация свойств

  • Конфигурация пространства имен Spring

  • Весенняя загрузка конфигурации

Для того, чтобы код выглядел более лаконичным и интуитивно понятным, он используется позже единообразно.propertiesСпособ настройки, импортshardingsphereсоответствующийsharding-jdbc-spring-boot-starterиsharding-core-commonПакет версии 4.0.0-RC1 для универсального использования.

2. Конфигурация фрагментации

<dependency>
	<groupId>org.apache.shardingsphere</groupId>
	<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
	<version>4.0.0-RC1</version>
</dependency>

<dependency>
	<groupId>org.apache.shardingsphere</groupId>
	<artifactId>sharding-core-common</artifactId>
	<version>4.0.0-RC1</version>
</dependency>

Подготовка завершена (построение mybatis повторяться не будет), а затем мы будем интерпретировать информацию о конфигурации шарда одну за другой.

Сначала мы определяем два источника данныхds-0,ds-1и добавьте основную информацию об источнике данных соответственно.

# 定义两个全局数据源
spring.shardingsphere.datasource.names=ds-0,ds-1

# 配置数据源 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://127.0.0.1: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

# 配置数据源 ds-1
spring.shardingsphere.datasource.ds-1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds-1.driverClassName=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-1.url=jdbc:mysql://127.0.0.1:3306/ds-1?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
spring.shardingsphere.datasource.ds-1.username=root
spring.shardingsphere.datasource.ds-1.password=root

После настройки источника данных добавьте стратегию подбазы данных и подтаблицы для таблицы, используйтеsharding-jdbcЧтобы делать шардинг и шардинг, нам нужно задать правила шардинга для каждой таблицы отдельно.

# 配置分片表 t_order
# 指定真实数据节点
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds-$->{0..1}.t_order_$->{0..2}

actual-data-nodesсвойство указывает реальный узел данных шарда,$является заполнителем, а {0..1} представляет фактическое количество разделенных таблиц базы данных.

ds-$->{0..1}.t_order_$->{0..2} Выражение эквивалентно 6 узлам данных

  • ds-0.t_order_0
  • ds-0.t_order_1
  • ds-0.t_order_2
  • ds-1.t_order_0
  • ds-1.t_order_1
  • ds-1.t_order_2
### 分库策略
# 分库分片健
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column=order_id
# 分库分片算法
spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression=ds-$->{order_id % 2}

Установите стратегию подбазы данных для таблицы, как указано выше.sharding-jdbcОн предоставляет четыре стратегии сегментирования. Чтобы быстро построить, мы сначала реализуем простейшую стратегию сегментирования встроенных выражений. В следующей статье мы представим подробное использование и сценарии использования четырех стратегий сегментирования.

database-strategy.inline.sharding-columnатрибут database-strategyДля стратегии подбиблиотеки inlineДля конкретной стратегии сегментирования sharding-columnПредставляет фрагментацию.

database-strategy.inline.algorithm-expression— конкретный алгоритм шардинга в рамках текущей стратегии,ds-$->{order_id % 2}выражение означает даorder_id Поле разделено по модулю на библиотеки. 2 – количество сегментированных библиотек. Разные стратегии соответствуют разным алгоритмам. Это также может быть наш пользовательский класс алгоритма сегментирования.


# 分表策略
# 分表分片健
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# 分表算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 3}
# 自增主键字段
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
# 自增主键ID 生成方案
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

Конфигурация подстратегии таблицы и стратегии подбазы данных аналогична, разница в том, что подтаблица таблицы может быть настроена с помощьюkey-generator.columnиkey-generator.typeУстановите первичный ключ автоинкремента и укажите схему генерации первичного ключа автоинкремента.SNOWFLAKEиUUIDДвумя способами, а также алгоритмом генерации первичного ключа пользовательского класса, последует подробное объяснение.

# 绑定表关系
spring.shardingsphere.sharding.binding-tables= t_order,t_order_item

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

# 配置广播表
spring.shardingsphere.sharding.broadcast-tables=t_config

Таблица вещания, откройте журнал парсинга SQL, вы можете ясно увидеть процесс парсинга фрагмента SQL

# 是否开启 SQL解析日志
spring.shardingsphere.props.sql.show=true

3. Проверьте шардинг

После настройки сегментирования нам не нужно изменять бизнес-код, мы можем напрямую добавлять, удалять, изменять и проверять бизнес-логику, а затем проверять эффект сегментирования.

В то же время мыt_order,t_order_itemТаблица вставляет 5 записей заказов, первичный ключ не указанorder_id,item_idзначение поля.

public String insertOrder() {

   for (int i = 0; i < 4; i++) {
       TOrder order = new TOrder();
       order.setOrderNo("A000" + i);
       order.setCreateName("订单 " + i);
       order.setPrice(new BigDecimal("" + i));
       orderRepository.insert(order);

       TOrderItem orderItem = new TOrderItem();
       orderItem.setOrderId(order.getOrderId());
       orderItem.setOrderNo("A000" + i);
       orderItem.setItemName("服务项目" + i);
       orderItem.setPrice(new BigDecimal("" + i));
       orderItemRepository.insert(orderItem);
   }
   return "success";
}

Увидев, что записи заказа были успешно распределены по разным библиотечным таблицам,order_idПоле также автоматически генерирует идентификатор первичного ключа, и базовая функция сегментирования завершена.

基础分片

таблица трансляцииt_configКаков будет эффект от вставки части данных?


public String config() {

    TConfig tConfig = new TConfig();
    tConfig.setRemark("我是广播表");
    tConfig.setCreateTime(new Date());
    tConfig.setLastModifyTime(new Date());
    configRepository.insert(tConfig);
    return "success";
}

есть во всех библиотекахt_configВсе таблицы выполняют этот SQL, а режим широковещательной таблицы и подписки на широковещательную рассылку MQ очень похож, и все подписанные клиенты получат одно и то же сообщение.

广播表

Простая проверка операции SQL не удалась. Далее попробуем более сложный совместный запрос. Мы уже ставилиt_order,t_order_itemТаблица задается как таблица привязки, и запрос выполняется непосредственно с таблицей.

关联查询

Через лог консоли обнаруживается, что после парсинга логической таблицы SQL остается толькоt_order_0иt_order_item_0Таблица связана для генерации SQL.

绑定表SQL

Что, если они не связывают таблицы друг с другом? Удалитьspring.shardingsphere.sharding.binding-tablesпопробуй.

Было обнаружено, что консоль разобрала 3 реальных табличных SQL-запроса и удалила их.order_idПосле его повторного выполнения в качестве условия запроса в результате было проанализировано 9 фрагментов SQL, и был выполнен декартово произведение запроса. Таким образом, преимущества таблицы привязки очевидны по сравнению с ней.

笛卡尔积查询

V. Резюме

Вышеупомянутое промежуточное ПО для подбиблиотеки и подтаблицыsharding-jdbcВкратце разобрались с основными понятиями шардинга, быстро построили случай подбазы данных и подтаблицы, но это только первый шаг в практике подбазы данных и подтаблицы.В следующей статье мы подробно представить конкретное использование и использование четырех стратегий сегментирования.Сценарии (должны знать и знать), и объяснит пользовательские распределенные первичные ключи, транзакции распределенной базы данных, управление распределенными службами, десенсибилизацию данных и т. д.

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


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