Давно это было.Из-за нового проекта в последнее время я был очень занят работой,поэтому давно не обновлял.Последнюю статью выложили.Ручная сборка кластера Redis и синхронизации master-slave MySQL (без Docker)После этого многих студентов заинтересовало разделение чтения и письма, упомянутое в статье в структуре master-slave Я планировал поделиться разделением чтения и письма со всеми в период Double Eleven, но моя работа никогда не прекращалась, поэтому Я нашел время, чтобы поделиться ими в эти выходные.
Что касается реализации разделения чтения и записи MySQL, есть два пути, первый способ заключается в том, что мы вручную реализуем логику на уровне кода, анализируем запросы на чтение или запросы на запись, распределяем по разным базам данных, реализуем разделение на чтение и запись; Второй способ основан на промежуточном программном обеспечении MYCAT для достижения эффекта чтения и записи; эти два способа я представлю, создам и проанализирую преимущества и недостатки в этом блоге.
Предварительное изучение принципа
Начиная с синхронизации master-slave в MySQL, наша архитектура базы данных с самого начала такая.
Основная библиотека отвечает за все операции чтения и записи, в то время как подчиненная библиотека только резервирует основную библиотеку.Как я уже говорил в предыдущей статье, я думаю, что если реализовано только одно резервное копирование, разделение чтения-записи и отказоустойчивость не могут быть выполнены ., не может уменьшить нагрузку ввода-вывода главного узла, такая архитектура ведущий-ведомый не кажется очень рентабельной.
Архитектура ведущий-подчиненный, которую мы хотим, заключается в том, что когда мы записываем данные, все запросы отправляются на главный узел, а когда нам нужно прочитать данные, все запросы отправляются на подчиненный узел. И несколько подчиненных узлов предпочтительно могут иметь балансировку нагрузки, чтобы максимизировать эффективность кластера.
Тогда такой архитектуры нам недостаточно для использования, нам нужно найти какой-то способ добиться разделения чтения-записи. Ну на самом деле есть два пути.
Метод 1: уровень кода реализует разделение чтения и записи.
Преимущество этого метода в том, что он более гибкий, мы можем определять правила чтения и записи в соответствии с его собственной логикой. Если этот метод используется, мы можем суммировать всю базу данных всей базы данных:
Способ 2. Используйте средний уровень (виртуальный узел) для пересылки запросов.
Основная особенность этого метода заключается в том, что мы строим новый виртуальный узел в дополнение к базе данных, и все наши запросы отправляются на этот виртуальный узел, а этот виртуальный узел перенаправляет запросы на чтение и запись в соответствующую базу данных.
Особенность этого метода заключается в том, что он строит независимый узел для получения всех запросов, вместо того, чтобы настраивать несколько источников данных в нашей программе, нашему проекту нужно только указать URL-адрес этого виртуального узла, а затем использовать этот виртуальный узел для обработки чтения и пишите запросы. Нет ли такой фразы,Профессиональные вещи оставлены профессиональным людям, наверное, это и имеется в виду. А существующее сейчас промежуточное ПО типа MyCat и есть такой "профессионал".
Затем я начну реализовывать два вышеупомянутых решения разделения чтения и записи,Слой кода для разделения чтения и записииИспользуйте промежуточное ПО для разделения чтения и записи
Вручную реализовать разделение чтения и записи
Существует много способов добиться разделения чтения и записи. Здесь я упомяну два. Первый — использовать MyBatis и Spring, написанный вручную перехватчик MyBatis для определения того, читается или пишется SQL, чтобы выбрать источник данных, и, наконец, передать его в Spring для внедрения источника данных, чтобы добиться разделения чтения и записи, во-вторых, использовать промежуточное ПО MyCat для настройки разделения чтения и записи, каждый метод имеет свои достоинства, вы можете выбрать в зависимости от ситуации.
Описание окружающей среды
Я использовал свой последний блог здесьРучная сборка кластера Redis и синхронизации master-slave MySQL (без Docker)Встроенная синхронизация master-slave MySQL, если у вас нет этой среды, вы можете сначала создать ее по сравнению с этим блогом. Но следует отметить, что версия MySQL 8.0 должна быть изменена на 5.7.
192.168.43.201:3306 Master
192.168.43.202:3306 Slave
Среда разработки:
IDE:Eclipse
Spring boot 2.1.7
MySQL 5.7
CentOS 7.3
Создайте новый проект Maven
Для удобства демонстрации SpringBoot используется в качестве базовой среды для тестирования, что позволяет сэкономить много XML-конфигураций, необходимых для Spring. Неважно, использовали ли вы SpringBoot, я продемонстрирую работу шаг за шагом.
Чтобы сделать тестовый проект максимально простым, нам не нужно слишком много настраивать другие вещи. Только некоторая базовая конфигурация и конфигурация источника данных.
@SpringBootApplication
public class ApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(ApplicationStarter.class, args);
}
}
запускать
Если появляется указанная выше информация, запуск выполнен успешно. Хм... Это должен быть блог, связанный с базой данных, кажется, слишком много говорится о SpringBoot.
Это означает, что с нашим проектом SpringBoot нет проблем, и он был успешно построен. Если вы не уверены, вы можете самостоятельно перейти по пути http://localhost:10001. Если есть 404 SpringBoot, это означает запуск проходит успешно.
Создайте новую сущность Student и создайте базу данных
package cn.objectspace.springtestdemo.domain;
public class Student {
private String studentId;
private String studentName;
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
}
package cn.objectspace.springtestdemo.dao;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import cn.objectspace.springtestdemo.domain.Student;
@Mapper
public interface StudentDao {
@Insert("INSERT INTO student(student_id,student_name)VALUES(#{studentId},#{studentName})")
public Integer insertStudent(Student student);
@Select("SELECT * FROM student WHERE student_id = #{studentId}")
public Student queryStudentByStudentId(Student student);
}
Тестовый класс:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ApplicationStarter.class})// 指定启动类
public class DaoTest {
@Autowired StudentDao studentDao;
@Test
public void test01() {
Student student = new Student();
student.setStudentId("20191130");
student.setStudentName("Object6");
studentDao.insertStudent(student);
studentDao.queryStudentByStudentId(student);
}
}
Если вы можете правильно вставить данные в базу данных, как показано на рисунке ниже, MyBatis успешно построен.
Официально построен
Благодаря вышеуказанным приготовлениям мы смогли читать и записывать в базу данных, но мы не добились разделения чтения и записи.Теперь мы начинаем реализовывать разделение чтения и записи базы данных.
Изменить application.yml
В нашем конфигурационном файле сейчас только один источник данных, и разделение чтения-записи определенно не будет одним источником данных, поэтому сначала нам нужно настроить несколько источников данных в application.yml.
Прежде всего, нам нужно создать два класса ConfigurationProperties.Этот шаг не является обязательным.Также можно настроить DataSource напрямую, но я все еще привык писать эти свойства.
MasterProperpties
package cn.objectspace.springtestdemo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "spring.datasource.master")
@Component
public class MasterProperties {
private String url;
private String username;
private String password;
private String driverClassName;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
}
SlaveProperties
package cn.objectspace.springtestdemo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "spring.datasource.slave")
@Component
public class SlaveProperties {
private String url;
private String username;
private String password;
private String driverClassName;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
}
DataSourceConfig
Эта конфигурация в основном предназначена для настройки источника данных ведущий-ведомый.
@Configuration
public class DataSourceConfig {
private Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
@Autowired
private MasterProperties masterProperties;
@Autowired
private SlaveProperties slaveProperties;
//默认是master数据源
@Bean(name = "masterDataSource")
@Primary
public DataSource masterProperties(){
logger.info("masterDataSource初始化");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(masterProperties.getUrl());
dataSource.setUsername(masterProperties.getUsername());
dataSource.setPassword(masterProperties.getPassword());
dataSource.setDriverClassName(masterProperties.getDriverClassName());
return dataSource;
}
@Bean(name = "slaveDataSource")
public DataSource dataBase2DataSource(){
logger.info("slaveDataSource初始化");
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(slaveProperties.getUrl());
dataSource.setUsername(slaveProperties.getUsername());
dataSource.setPassword(slaveProperties.getPassword());
dataSource.setDriverClassName(slaveProperties.getDriverClassName());
return dataSource;
}
}
Переключение источников динамических данных
В основном здесь используется AbstractRoutingDataSource, предоставляемый Spring, который обеспечивает функцию динамического источника данных и может помочь нам добиться разделения чтения и записи. Его defineCurrentLookupKey() может определить, какой источник данных в конечном итоге используется.Здесь мы сами создаем DynamicDataSourceHolder, чтобы передать ему тип источника данных (главный, подчиненный).
Наконец, мы реализуем разделение чтения и записиосновнойТеперь этот класс может решить, следует ли читать SQL или писать SQL, чтобы выбрать источник данных и, наконец, вызвать метод setDbType DynamicDataSourceHolder для передачи типа источника данных.
С помощью вышеприведенной программы мы уже можем реализовать разделение чтения и записи, но на это все еще довольно грязно смотреть. Итак, повторно объедините приведенный выше код здесь.
На самом деле логика не сложная:
Для настройки нескольких источников данных через @Configuration.
Используйте перехватчик MyBatis, DynamicDataSourceInterceptor, чтобы определить, читается или пишется оператор SQL.Если он прочитан, вызовите DynamicDataSourceHolder.setDbType("slave"), в противном случае вызовите DynamicDataSourceHolder.setDbType("master").
С помощью метода defineCurrentLookupKey() объекта AbstractRoutingDataSource верните DynamicDataSourceHolder.getDbType(), то есть источник данных, который мы установили в перехватчике.
Выполните SQL для внедренного источника данных.
контрольная работа
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ApplicationStarter.class})// 指定启动类
public class DaoTest {
@Autowired StudentDao studentDao;
@Test
public void test01() {
Student student = new Student();
student.setStudentId("20191130");
student.setStudentName("Object6");
studentDao.insertStudent(student);
studentDao.queryStudentByStudentId(student);
}
}
Результаты теста:
На данный момент полностью реализовано разделение чтения и записи на уровне кода.
Реализуйте разделение чтения-записи и аварийное переключение на основе промежуточного программного обеспечения MyCat.
Введение
В вышеприведенном мы реализовали разделение чтения и записи базы данных с помощью рукописного кода, но я не знаю, нашли ли вы его, я использую только один мастер и один слейв. ТакПочему я реализую только разделение чтения-записи одного ведущего и одного ведомого в среде с одним ведущим и двумя ведомыми?Потому что я не буду писать, чтобы реализовать разделение чтения-записи одного мастера и нескольких ведомых на уровне кода. Затем предположим, что кластер базы данных состоит из более чем одного главного и двух подчиненных устройств, ноМастер из трех, четыре из мастера, мультимадер из несколькихШерстяная ткань? еслиГлавный узел не работает, что делать??
Каждый раз, когда нода динамически добавляется, нам приходится заново модифицировать наш код, что не только сильно нагружает разработчиков, но и не соответствует принципу открытости-закрытости.
Так что следующий MyCat должен решить такую проблему. И я буду непосредственно использовать демонстрацию среды одного мастера и двух подчиненных.
О MyCat
Официальная документация находится непосредственно здесь.
Большой кластер базы данных с полностью открытым исходным кодом для разработки корпоративных приложений.
Расширенная база данных, которая поддерживает транзакции, ACID и может заменить MySQL.
База данных корпоративного уровня, которую можно рассматривать как кластер MySQL для замены дорогого кластера Oracle.
Новый SQL Server, объединяющий технологию кэширования памяти, технологию NoSQL и большие данные HDFS.
Новое поколение продуктов баз данных корпоративного уровня, сочетающих в себе традиционные базы данных и новые распределенные хранилища данных.
Новый промежуточный продукт для баз данных
Описание окружающей среды
MyCat 192.168.43.90
MySQL master 192.168.43.201
MySQL slave1 192.168.43.202
MySQL slave2 192.168.43.203
База данных MySQL, подключенная к предыдущему блогу, состоит из одного главного и двух подчиненных устройств, ноВерсия MySQL должна быть изменена с 8.0 на 5.7, иначе будет проблема с паролем и вы не сможете подключиться.
Кроме того, нам нужно создать учетную запись для MyCat в каждой базе данных и назначить разрешения:
CREATE USER 'user_name'@'host' IDENTIFIED BY 'password';
GRANT privileges ON databasename.tablename TO ‘username’@‘host’;
--可以使用下面这句 赋予所有权限
GRANT ALL PRIVILEGES ON *.* TO ‘username’@‘host’;
--最后刷新权限
FLUSH PRIVILEGES;
Перед запуском убедитесь, что построение библиотеки master-slave прошло успешно:
Я не буду здесь говорить о том, как установить MyCat, на Baidu есть много постов, и нет никаких проблем в том, чтобы следовать приведенному выше руководству шаг за шагом. Давайте сосредоточимся на двух файлах конфигурации, связанных с нашей конфигурацией MyCat:схема.xml и сервер.xml, конечно, есть rules.xml, но подтаблица подбазы данных здесь не представлена, поэтому пока об этом не упоминается.
Описание файла конфигурации
server.xml
Открываем mycat install файлы /conf/server.xml в каталоге, этот конфигурационный файл длиннее, смотря больше затратит мозг, но на самом деле для начала нам нужно для настройки места не много, так что не сильно боимся этот длинный профиль. (Вообще-то в конце предыдущей статьи я сказал, что лицо новой технологии нельзя не знать, когда сначала заставляют, шаг за шагом анализировать и принимать его, отталкивая) после файла конфигурации, наверное, такой упрощенный структура .
Это кажется намного проще?На самом деле для Server.xml мы в основном настраиваем следующий пользовательский модуль.Расширяем его и фокусируемся на этой части конфигурации.
user представляет пользователя MyCat, у нас будет пользователь, когда мы будем использовать MySQL,MyCat как виртуальный узел, мы можем представить его как MySQL, поэтому, естественно, у него также должен быть пользователь. Но его пользователь не создается нами с помощью команды, а настраивается непосредственно в конфигурационном файле.После того, как мы авторизуемся в MyCat, мы авторизуемся с логином и паролем здесь. Что касается того, как настроить, я написал это в приведенной выше конфигурации. Следите за собой, и у вас все будет хорошо.
schema.xml
Откройте conf/schema.xml в каталоге установки MyCat, этот файл конфигурацииэто файл конфигурации, на который нам нужно обратить внимание, потому что наше разделение чтения-записи, подтаблица подбазы данных и отработка отказа настроены в этом файле конфигурации. Но этот конфигурационный файл не длинный, мы можем разобрать его по крупицам.
во-первыхэто содержимое тега. Эта метка в основном предназначена для создания виртуальной базы данных для MyCat.Здесь настраивается база данных, которую мы видим при подключении к MyCat.Подбаза данных и подтаблица также в основном настраиваются на этой вкладке.. в этом тегеnameАтрибут предназначен для указания имени виртуальной базы данных, а также имени библиотеки базы данных, которую мы видим при подключении к MyCat.dataNodeОно соответствует имени в метке dataNode ниже, представляя, что эта виртуальная база данных привязана к dataNode ниже.
вторая этикеткаэто метка, эта метка связана с базой данных в нашей реальной базе данных,nameАтрибут — это имя, которое мы настраиваем для этого узла данных. Следует отметить, что это имя должно соответствовать содержимому узла данных в теге схемы.databaseСвойство записывается с именем реальной базы данных в нашей реальной базе данных. иdataHostСодержимое должно соответствовать значению атрибута имени в следующем теге.
третья вкладкаЧто я хочу сказать, так это метка.Эта метка связана с разделением master-slave и read-write нашей реальной базы данных.Что это значит? В этом теге есть два вложенных тега, которые представляют нашунаписать библиотекуичитать библиотеку, настроенная библиотека может использоваться для чтения или записи, а настроенная библиотека может использоваться только для чтения.
Видно, что конфигурация schema.xml связана одна за другой, и каждый тег имеет атрибуты, связанные друг с другом. Наш окончательный сконфигурированный schema.xml должен выглядеть так:
Выше мы сделали базовую интерпретацию двух файлов конфигурации MyCat, поэтому теперь мы начнем строить разделение чтения и записи на основе MyCat. У меня здесь три базы данных, одна главная и две подчиненные, еще раз повторю среду:
192.168.43.201 главная библиотека
192.168.43.202 подчиненная библиотека
192.168.43.203 подчиненная библиотека
Тогда конфигурация для server.xml и schema.xml выглядит следующим образом:
Правильно видно, что в MyCat есть база данных с именем MyCat, и эта база данных виртуализирована нами и реально не существует.На самом деле играет роль именно наша конфигурация.
Это может доказать, что наше подключение mycat к реальной базе данных прошло успешно. Затем мы начнем доказывать разделение чтения и письма Что такое разделение чтения и письма?То есть операция чтения данных читается из ведомой библиотеки, а основная библиотека отвечает только за операции записи, Давайте начнемпроверять.
Перед проверкой нам нужно установить журнал MyCat в режим отладки, потому что в информационном режиме невозможно показать, в какую базу данных перенаправляется оператор SQL для запроса в журнале..
Как настроить:
Откройте файл conf/log4j2.xml.
выполнить оператор вставки:
INSERT INTO student(student_id,student_name) VALUES('20191130','Object');
Посмотреть журнал:
Видно, что инструкция INSERT написана в 201, а 201 — это Master-библиотека, то есть библиотека записи.
напиши мы приедемвыполнить оператор чтения:
SELECT * FROM student;
Видно, что оператор SELECT выполняется в 202, а 202 — это библиотека Slave, то есть библиотека чтения.
Сделай это снова:
В это время выполняется оператор чтения в 203 или читается библиотека.Эти две библиотеки чтения читаются на основе правил балансировки нагрузки..
Это завершает настройку разделения чтения-записи. Когда нам нужно выполнить INSERT/UPDATE/DELETE, мы будем писать непосредственно в ведущую, а затем синхронизироваться с подчиненной библиотекой.Когда мы хотим выполнить операцию SELECT, мы будем читать в вместо этого Ведомый. , не влияет на написание Мастера,Это разделение чтения и записи расширяет функцию синхронизации master-slave MySQL, что может повысить производительность базы данных при аварийном восстановлении и резервном копировании..
Переключение конфигурации MyCat
Мы уже сделали MyCat на вышеуказанномразделение чтения-записиконфигурации, то мы смело предполагаем, что еслиНаша база данных Master внезапно выходит из строя, поэтому весь кластер теряет функцию записи??
Этот ответ до отказа.определенно, Когда основная библиотека не работает, подчиненная библиотека как библиотека чтения не будет иметь функции записи, а весь кластер лишится функции записи, чего мы не хотим видеть.
Сценарии, которые мы хотим видеть, следующие:Когда главная библиотека выходит из строя, подчиненная библиотека автоматически становится главной библиотекой, которая берет на себя функцию записи и обеспечивает доступность всего кластера..
Затем мы начнем настройку, на самом деле, идея очень проста, в теге mycat наблюдается свойство SwitchPype, которая определяет условие для переключения.
switchType относится к режиму переключения, и в настоящее время существует 4 значения:
switchType='-1' означает отсутствие автоматического переключения
switchType='1' Значение по умолчанию, означающее автоматическое переключение
switchType='2' Определяет, следует ли переключаться, основываясь на состоянии синхронизации master-slave MySQL.
switchType='3' основан на механизме переключения галерейного кластера MySQL (подходит для кластера) (1.4.1), а оператор сердцебиения показывает состояние, подобное 'wsrep%'.
Мы напрямую изменяем switchType на 2, а затем настраиваем две библиотеки чтения в качестве первой библиотеки записи.тот же уровеньписательская библиотека.
Теперь давайте остановим основную библиотеку, а затем выполним операцию записи, чтобы посмотреть, что получится в результате.
service mysqld stop
Журнал MyCat:
воплощать в жизньINSERT INTO student(student_id,student_name)VALUES('test','testdown');
Журналы MyCat
Видно, что когда мы заканчиваем выполнение этого оператора, он автоматически переключается на базу данных 202 для записи, а 202 является слейвом вместо мастера, а это означает, что MyCat автоматически переключил базу данных для записи, и наш кластер MySQL все еще может обеспечить написать функцию.
Конечно, в настоящее время наша архитектура MySQL master-slave разрушена, и если нам нужно восстановить структуру master-slave, нам нужно вручную восстановить нашу архитектуру master-slave. Нам нужно использовать 201 и 203 как Slave и 202 как Master, т.к. у Master самые полные данные.
Анализ преимуществ и недостатков
Что касается преимуществ и недостатков этих двух методов, я считаю, что студенты, которые внимательно прочитают эту статью, получат глубокий опыт.
Слой кода для разделения чтения и записиОсновным преимуществом являетсяГибкость, вы можете настроить разработку правил разделения чтения-записи в соответствии с различными потребностями., но его недостаток также весьма очевиден, то есть, когда мы динамически увеличиваем или уменьшаем количество master-slave библиотек, нам нужно вносить более или менее модификацию кода. И когда основная база данных выходит из строя, если мы не реализуем соответствующую логику аварийного восстановления, весь кластер базы данных потеряет функцию внешней записи.
Используйте промежуточное ПО MyCat для разделения операций чтения и записи., преимущества очень очевидны, нам нужно только настроить, чтобы наслаждаться повышением эффективности, вызванным разделением чтения и записи, без написания строки кода, и когда основная библиотека не работает, мы также можем автоматически переключать библиотеку ведущий-ведомый через конфигурации, Таким образом, даже если основная база данных выйдет из строя, весь наш кластер не потеряет функцию записи. Недостатком может быть то, что мы должны платить за сервер как за виртуальную ноду, ведь серверу тоже нужна стоимость.
Как выбрать между двумя способами: Если ваш текущий проект относительно небольшой, или это просто выпускной проект, курсовой дизайн и т.д., и нет необходимости динамически увеличивать или уменьшать базу данных, то вам будет более подходящим реализовать разделение чтения и написание базы данных самостоятельно.Когда придет время, вы можете объяснить (чжуан) объяснить (би) с вашим репетитором и одноклассниками строка за строкой кода. Если проект относительно большой, узлы базы данных могут быть увеличены или уменьшены, и требуются такие функции, как переключение ведущий-ведомый, тогда используйте второй метод. Реализация такой конфигурации может снизить вероятность засорения канализационной трубы при мытье головы на следующий день.