Учебник по началу работы с ShardingSphere-JDBC

Java

Оригинальный адрес:Учебник по началу работы с ShardingSphere-JDBC

Введение

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

Главный герой этой статьиShardingSphere-JDBC.

2. Основное введение

Apache ShardingSphereЭто экосистема, состоящая из набора распределенных баз данных с открытым исходным кодом и состоящая из трех продуктов: JDBC, Proxy и Sidecar (в разработке), которые можно развертывать независимо и использовать в сочетании с гибридным развертыванием. Все они обеспечивают стандартизированное горизонтальное масштабирование данных, распределенные транзакции и распределенное управление и могут применяться к различным сценариям приложений, таким как изоморфизм Java, гетерогенные языки и облачные среды.

ShardingSphere-JDBCдаApache ShardingSphereПодмодуль в Java, позиционируемый как облегченная среда Java, предоставляет дополнительные услуги на уровне JDBC Java. Он использует клиент для прямого подключения к базе данных и предоставляет услуги в виде пакетов jar без дополнительного развертывания и зависимостей.Его можно понимать как расширенную версию драйвера JDBC, которая полностью совместима с JDBC и различными ORM-фреймворками.

Его особенности:

  1. Работает с любой инфраструктурой ORM на основе JDBC, такой как: JPA, Hibernate, Mybatis, Spring JDBC Template или с использованием JDBC напрямую.
  2. Поддержка любого стороннего пула подключений к базе данных, например: DBCP, C3P0, BoneCP, Druid, HikariCP и т. д.
  3. Поддерживает любую базу данных, реализующую спецификацию JDBC, в настоящее время поддерживает MySQL, Oracle, SQLServer, PostgreSQL и любую базу данных, соответствующую стандарту SQL92.

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

2.1 Список функций

разделение данных

  • Подбиблиотека и подтаблица
  • разделение чтения-записи
  • Настройка стратегии шардинга
  • Децентрализованный распределенный первичный ключ

Распределенная транзакция

  • Стандартизированный интерфейс транзакций
  • Строго согласованные транзакции XA
  • гибкие дела

Управление базой данных

  • Распределенное управление
  • Эластичное масштабирование
  • Визуальное отслеживание ссылок
  • шифрование данных
Примечание. ShardingSphere-JDBC — это инструмент не для подбазы данных и подтаблицы, а для решения проблем с маршрутизацией и запросами, вызванных подбазой данных и подтаблицей.

2.2 Основные концепции

Логическая таблица:Общий термин для таблиц с одинаковой логикой и структурой данных для горизонтально разделенной базы данных (таблицы). Пример: данные заказа разделены на 10 таблиц в соответствии с мантиссом первичного ключа, а именно от t_order_0 до t_order_9, и их логическое имя таблицы — t_order.

Реальная таблица:Физические таблицы, которые фактически существуют в сегментированной базе данных. Это от t_order_0 до t_order_9 в предыдущем примере.

узел данных:Наименьшая единица фрагментации данных. Он состоит из имени источника данных и таблицы данных, например: ds_0.t_order_0.

Таблица привязки:Относится к основной таблице и подтаблице с согласованными правилами сегментирования. Например, таблица t_order и таблица t_order_item сегментированы в соответствии с order_id, поэтому эти две таблицы связаны друг с другом. Запрос ассоциации с несколькими таблицами между таблицами привязки не будет отображаться декартовой ассоциацией продуктов, и эффективность запроса ассоциации будет значительно повышена.

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

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

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

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

Стратегия разделения:Включая ключ сегментации и алгоритм сегментации, которые извлекаются независимо из-за независимости алгоритма сегментации. Что реально можно использовать для операций шардирования, так это ключ шардирования + алгоритм шардирования, то есть стратегию шардирования.

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

3. Практические занятия

В качестве примера возьмем горизонтальную подбиблиотеку, как простейший случай реального боя.

3.1 Создать базу данных и таблицу

CREATE TABLE `t_order_1` (
	`order_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
	`user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '用户 id',
	`total_price` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单价格',
	`state` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '订单状态',
	`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
	`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
	PRIMARY KEY (`order_id`),
	INDEX `user_id` (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

CREATE TABLE `t_order_2` (
	`order_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
	`user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '用户 id',
	`total_price` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单价格',
	`state` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '订单状态',
	`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
	`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
	PRIMARY KEY (`order_id`),
	INDEX `user_id` (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

Дополнение: t_order_1 и t_order_2 — настоящие таблицы, в последнемSQLПри записи мы используем t_order как логическую таблицу для записи.

3.2 Знакомство с зависимостями

Изменить элементpom.xmlдокумент:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<!-- jdbc 驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>

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

3.3 Настройка правил фрагментации

Исправлятьapplication.propertiesдокумент

spring.application.name=sharding-jdbc

mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

# shardingsphere 配置开关,如果使用 java api 配置方式,需要修改为 false
spring.shardingsphere.enabled=true

# 定义数据源
spring.shardingsphere.datasource.names=m1

# 下边用到的 m1 就是上边定义的
spring.shardingsphere.datasource.m1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.jdbc-url=jdbc:mysql://localhost:3306/db_order?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=tiger

# 下边 t_order 是逻辑表,真实查询对应真实的 t_order_1 和 t_order_2
# 指定 t_order 表的主键生成策略为 SNOWFLAKE,order_id 就是 t_order 表的主键
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

# 指定 t_order 表的数据分布情况,配置数据节点
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=m1.t_order_$->{1..2}

# 指定 t_order 表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
# order_id 值为奇数插入到 t_order_2 表,为偶数插入到 t_order_1 表
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id%2+1}

# 打开 sql 输出日志
spring.shardingsphere.props.sql.show = true

logging.level.root=info
logging.level.org.springframework.web=info
logging.level.com.light.sharding.jdbc=debug

3.4 Реализация уровня сохраняемости

Определите интерфейс картографа:

@Mapper
public interface OrderMapper {

    /**
     * 插入
     * @param order
     */
    void insert(Order order);

    /**
     * 批量查询
     * @param idList
     * @return
     */
    List<Order> selectListByIds(@Param("idList") List<Long> idList);
}

Файл сопоставления маппера:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.light.sharding.jdbc.mapper.OrderMapper">

    <insert id="insert" parameterType="com.light.sharding.jdbc.model.Order">
        INSERT INTO t_order(user_id, total_price, state, create_time, update_time)
        VALUES(#{userId}, #{totalPrice}, #{state}, #{createTime}, #{updateTime})
    </insert>

    <select id="selectListByIds" resultType="com.light.sharding.jdbc.model.Order">
        SELECT order_id, user_id, total_price, state FROM t_order WHERE order_id IN
        <foreach collection="idList" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
</mapper>

Уведомление: SQLнаписано с использованиемлогическая таблица.

3.5 Модульное тестирование

Протестируйте операцию вставки:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShardingJdbcApplication.class)
public class OrderMapperTest {

    @Autowired
    private OrderMapper orderMapper;

    @Test
    public void testInsert() {
        for (int i = 0 ; i < 10; i++){
            Order order = new Order();
            order.setUserId(1L);
            order.setState(0);
            order.setTotalPrice(new BigDecimal((i + 1) * 5));
            order.setCreateTime(LocalDateTime.now());
            order.setUpdateTime(order.getCreateTime());
            this.orderMapper.insert(order);
        }
    }
}

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

Как видно из рисунка выше, вставленный результат данных соответствует правилам конфигурации.


Операция тестового запроса:

@Test
public void testSelectList() {
    List<Long> idList = Arrays.asList(593141944457101312L, 593141944922669057L);
    List<Order> orderList = this.orderMapper.selectListByIds(idList);
    System.out.println(orderList);
}

мы начинаем сt_order_1а такжеt_order_2Возьмите кусок данных для проверки запроса, и результат выполнения будет следующим:

Согласно журналу,ShardingSphere-JDBCотправить на оба столаSQLсделать запрос.

3.6 конфигурация Java-API

Этот раздел используется как дополнение к методу конфигурации.Если вам не нравится использовать описанный выше метод с файлом конфигурации, вы можете использовать следующую конфигурацию:

Создайте класс конфигурации:

@Configuration
public class ShardingJdbcConfig {

    // sharding‐Jdbc 数据源
    @Bean
    public DataSource getShardingDataSource() throws SQLException {
        // 定义数据源,此处我们定义数据源名称为 m2
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_order?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true");
        dataSource.setUsername("root");
        dataSource.setPassword("tiger");
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        dataSourceMap.put("m2", dataSource);
        // 分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        // 其他配置
        Properties properties = new Properties();
        properties.put("sql.show","true");
        return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties);
    }

    // 分片规则
    private TableRuleConfiguration getOrderTableRuleConfiguration() {
        // 指定 t_order 表的数据分布情况,配置数据节点
        TableRuleConfiguration result = new TableRuleConfiguration("t_order","m2.t_order_$->{1..2}");
        // 指定 t_order 表的分片策略,分片策略包括分片键和分片算法
        result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id%2+1}"));
        result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
        return result;
    }

    // 定义主键生成策略
    private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
        return new KeyGeneratorConfiguration("SNOWFLAKE","order_id");
    }
}

Мы определяем имя источника данных какm2.

Закройте файл конфигурации и измените файл application.properties:

spring.shardingsphere.enabled=false

Выполните запрос, и результат будет следующим:

Как видно из лога на рисунке, используется источник данных с именем m2, запрос запроса выполнен успешно.

4. Процесс исполнения

когдаSharding-JDBCполучилSQLКогда оператор выполняется, он будет выполняться последовательноSQL解析 => 查询优化 => SQL路由 => SQL改写 => SQL执行 => 结果归并и, наконец, вернуть результат выполнения.

4.1 Разбор SQL

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

Например, следующееSQLНапример:

SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18

Для простоты понимания ключевые слова в абстрактном синтаксическом деревеTokenЗеленым цветом обозначена переменнаяTokenОбозначено красным, серый означает, что требуется дальнейшее разделение.

Наконец, поvisitorМодель предметной области создается путем обхода абстрактного синтаксического дерева, а контекст, необходимый для сегментирования, уточняется с помощью модели предметной области (SQLStatement), а места, которые, возможно, необходимо переписать, помечаются. Контекст синтаксического анализа для сегментирования включает в себя элементы выбора запроса (Выбор элементов), информацию таблицы (Таблица), условие сегментирования (Условие сегментирования), информацию о первичном ключе с автоинкрементом (Автоинкрементный первичный ключ), информацию о сортировке (Порядок), информацию о группировке (Группировать). By) и пейджинговой информации (Limit, Rownum, Top).SQLПроцесс разбора необратим, один за другимTokenсогласно сSQLИсходный порядок анализируется последовательно, и производительность очень высока. Рассмотрение различных баз данныхSQLСходства и различия диалектов предоставляются в модуле синтаксического анализа различных баз данных.SQLДиалектный словарь.

4.2 Оптимизация запросов

Слияние и оптимизация условий сегментирования, таких как ИЛИ и т. д.

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

Сопоставьте политику сегментирования, настроенную пользователем, в соответствии с контекстом синтаксического анализа и сгенерируйте путь маршрутизации. Для тех, у кого есть осколочные ключиSQL, в соответствии с различными ключами сегментов, его можно разделить на однослойную маршрутизацию (оператор ключа сегмента — знак равенства), многослойную маршрутизацию (оператор ключа сегмента —IN) и маршрутизация диапазона (оператор ключа сегментаBETWEEN). без осколочного ключаSQLИспользуется широковещательная маршрутизация.

4.4 Перезапись SQL

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

Следующий столбец является примером, если логический SQL:

SELECT order_id FROM t_order WHERE order_id = 1;

Предположим, чтоSQLКогда ключ осколка order_id настроен и order_id=1, он будет перенаправлен в таблицу осколков 1. Затем после перезаписиSQLДолжно быть:

SELECT order_id FROM t_order_1 WHERE order_id = 1;

4.5 Выполнение SQL

ShardingSphereПринять набор автоматических механизмов выполнения, отвечающих за маршрутизацию и перезапись реальногоSQLБезопасная и эффективная отправка в базовый источник данных для выполнения. это не простоSQLпройти черезJDBCОн отправляется непосредственно в источник данных для выполнения; он не помещает запрос на выполнение напрямую в пул потоков для параллельного выполнения. Это больше связано с балансировкой потребления создания соединения с источником данных и использованием памяти, а также с максимальным рациональным использованием параллелизма и другими проблемами.

4.6 Объединение результатов

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

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

5. Ссылки

Официальный сайт ShardingSphere