Sharding-JDBC: как оптимизировать объем запросов?

распределенный

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

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

Ниже приведена текущая ситуация:

单库读写操作

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

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

На следующей картинке состояние после улучшения:

主从架构

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

Xiao Wang - решительный и решительный человек с сильной мобильностью.У него сразу в голове есть план.Недостаточно настроить несколько источников данных, а потом использовать разные источники данных для операций с данными!

Псевдокод выглядит следующим образом:

// 主数据源
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
//指定数据源配置前缀
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}

// 从数据源
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@Primary //在同样的DataSource中,首先使用被标注的DataSource  
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}

Предположим, мы оперируем базой данных с помощью JdbcTemplate:

@Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}
@Bean(name = "secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

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

Итак, Сяо Ван нашел меня, я сердечный человек. Теперь, когда я нашел это, я должен помочь.Конечно, я не помогаю Сяо Вану писать код, а просто даю ему идеи + решения.

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

После моего руководства Сяо Ван успешно использовал Sharding-JDBC для разделения чтения и записи.Позвольте мне поделиться с вами следующими шагами.

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


CREATE DATABASE `ds_0` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `ds_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

CREATE TABLE `user`(
	id bigint(64) not null,
	city varchar(20) not null,
	name varchar(20) not null,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Создайте пользовательскую таблицу в библиотеках ds_0 и ds_1 соответственно для демонстрации работы с данными.

Шаг 2: Создайте проект Maven и добавьте необходимые зависимости. Ниже будет размещен только Sharding-JDBC. Для остальных я дам адрес исходного кода для вашей справки:

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

Шаг 3. Настройте источник данных с разделением чтения и записи.

# 数据源名称集合,对应下面数据源配置的名称
spring.shardingsphere.datasource.names=master,slave

# 主数据源
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://localhost:3306/ds_0?characterEncoding=utf-8
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456

# 从数据源
spring.shardingsphere.datasource.slave.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave.url=jdbc:mysql://localhost:3306/ds_1?characterEncoding=utf-8
spring.shardingsphere.datasource.slave.username=root
spring.shardingsphere.datasource.slave.password=123456

# 读写分离配置
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
# 最终的数据源名称
spring.shardingsphere.masterslave.name=dataSource
# 主库数据源名称
spring.shardingsphere.masterslave.master-data-source-name=master
# 从库数据源名称列表,多个逗号分隔
spring.shardingsphere.masterslave.slave-data-source-names=slave

load-balance-algorithm-type используется для настройки типа алгоритма балансировки нагрузки подчиненной библиотеки, необязательные значения: ROUND_ROBIN (циклический перебор), RANDOM (случайный)

После завершения настройки вы можете вставить данные для запроса и вставки теста.Это не влияет на то, какая структура ORM используется прикладным уровнем, вы можете использовать JDBCTemplate, прежде чем мы сможем использовать Mybatis. Ждать

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

GitHub.com/Йинджи Хуан/Да…

Если вы думаете, что это хорошо, не забудьте дать мне звезду!

Также есть проблема, которая часто возникает в архитектуре разделения чтения-записи, то есть как решить проблему задержки чтения?

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

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

Репликация master-slave в mysql5.7 является многопоточной, а это означает, что скорость будет выше, но не может быть гарантировано немедленное чтение на 100%.Мы можем решить эту проблему двумя способами:

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

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

public List<User> list() {
	// 强制路由主库
	HintManager.getInstance().setMasterRouteOnly();
	return userRepository.list();
}

猿天地