digital-garden/dev/database/mysql/Репликация в MySQL.md
Struchkov Mark 044f45a130
All checks were successful
continuous-integration/drone/push Build is passing
Репликация в MySQL.md
2024-09-17 22:01:31 +03:00

128 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
aliases:
tags:
- maturity/🌱
date:
- - 2024-05-28
zero-link:
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
parents:
- "[[../../architecture/highload/Репликация БД|Репликация БД]]"
linked:
- "[[Журналы в MySQL]]"
link:
---
## Тезисы
- На slave можно реализовать другую схему БД, построить другие индексы.
- Можно использовать [libslave](libslave.md), чтобы "притвориться" репликой.
- Мастер многопоточен, а слейв - нет. Вроде исправлено в новых версиях SQL.
- В 5.6 версии можно реплицировать параллельно несколько БД
- В 5.7 версии можно реплицировать параллельно одни и те же таблицы
- Обязательно убедиться, что работают GUID идентификация транзакций.
- **Репликация сильно зависит от версии MySql**
- Всегда логическая репликация, модель master-slave, pull распространение
- 4.1 = асинхронная, SBR, logposs
- 5.1 = +RBR, +mixed. Дефолт mixed
- 5.6 = +semisync, +mtslave (per-db), +slavedelay, +GTID
- 5.7 = + mtslave, +master-master (plugin), +default-RBR (image=full?!), groupcommit
## Схема работы репликации
![[Архитектура MySQL#^42f122]]
Физический слой хранилища должен писать журнал для работы транзакций (Write-Ahead Log). По идее, его можно было бы использовать для репликации, как в PostgreSQL, но логический слой ничего не знает про физический и не может использовать тот же журнал. Поэтому при включении репликации на логическом уровне master начинает вести свой журнал, называемый Binary Log.
Механизм работы следующий:
- **Запись изменений в бинарный лог**: Все изменения данных записываются в бинарный лог (Binary Log) на мастере. Бинарный лог хранит последовательность всех транзакций, которые изменяют данные.
- **Передача бинарного лога на реплики**: Мастер передает бинарный лог на реплики. Для этого используются потоки binlog dump на мастере и I/O потоки на репликах. В отличие от PostgreSQL, используется pull модель распространения, то есть реплики сами забирают изменения с master.
- **Применение изменений на репликах**: Реплики считывают бинарный лог и применяют изменения к своим копиям данных, поддерживая синхронизацию с мастером.
![](../../../meta/files/images/Pasted%20image%2020240712083105.png)
Binary Log в MySQL может записывать данные в разных форматах, в зависимости от настроек журнала. Рассмотрим основные из них:
- [Statement Based Replication (SBR)](Statement%20Based%20Replication%20(SBR).md)
- [Row Based Replication (RBR)](Row%20Based%20Replication%20(RBR).md)
- [Mixed binlog format](Mixed%20binlog%20format.md)
**Процесс записи данных операции в MySQL**
- INSERT INTO test VALUES (123, 'hello')
- Записываем в таблицу на мастере mysqld
- Записываем в binary log на мастере
- Записываем в relay log на слейве
- таблица на слейве mysqld
Рабочие потоки ([MySQL Replication Threads](https://dev.mysql.com/doc/refman/8.0/en/replication-threads.html)):
- binlog dump thread. Сохраняет лог транзакций на master
- slave I/O thread. Спуливает изменения на slave с master
- slave SQL thread. Применяет изменения на slave
MySQL не решает из коробки проблемы кластеризации. Из коробки нет переключений со slave на master если мастер сдох, распределения нагрузки и так далее. Можно решить дополнительным софтом:
- MHA (MySQL Master HA)
- MySQL Failover (Oracle)
- Orchestrator
## Фильтрация репликации
Можно реплицировать данные частично, но это стоит использовать осторожно. Например, это не работает с [Групповая репликация](../../architecture/highload/Групповая%20репликация.md)
Опции:
- replicate_do_db
- replicate_ignore_db
- replicate_do_table
[MySQL - CHANGE REPLICATION FILTER Statement](https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html)
![](../../../meta/files/images/Pasted%20image%2020240605091913.png)
***
- В InnoDB, заметьте, т.е. у нас архитектура разделяет репликацию выше, а storage engine ниже. Но storage engine, для того, чтобы репликация работала, должен, грубо говоря, замедлять insert'ы в таблицу.
- Другая проблема состоит в том, что мастер выполняет запросы параллельно, т.е. одновременно, а слэйв их может применять последовательно. Возникает вопрос а почему слэйв не может применять их параллельно? На самом деле, с этим все непросто. Есть теорема о сериализации транзакций, которая рассказывает, когда мы можем выполнять запросы параллельно, а когда последовательно. Это отдельная сложная тема, разберитесь в ней, если вам интересно и нужно, например, почитав по ссылке [http://plumqqz.livejournal.com/387380.html](http://plumqqz.livejournal.com/387380.html).
- В MySQL репликация упирается в процессор. Это прекрасная картинка большой, мощный сервер, 12 ядер. Работает одно ядро, заодно занято репликацией. Из-за этого реплика задыхается. Это очень грустно.
Для того чтобы выполнять запросы параллельно существует группировка запросов. В InnoDB есть специальная опция, которая управляет тем, как именно мы группируем транзакции, как именно мы их пишем на диск. Проблема в том, что мы можем их сгруппировать на уровне InnoDB, а уровнем выше на уровне репликации этой функциональности не было. В 2010 г. Кристиан Нельсен из MariaDB реализовал такую фичу, которая называется Group Binary Log Commit. Получается, мы журнал повторяем на двух уровнях Storage Engine и репликация, и нам нужно таскать фичи из одного уровня на другой. Это сложный механизм. Более того, нам нужно одновременно консистентно писать сразу в два журнала two-phase-commit. Это еще хуже.
На следующей картинке мы видим два графика:
![](../../../meta/files/images/Pasted%20image%2020240528090119.png)
Синий график демонстрирует то, как масштабируется InnoDB, когда мы ему добавляем треды. Накидываем треды число транзакций, которые он обрабатывает, возрастает. Красная линия показывает ситуацию, когда включена репликация. Мы включаем репликацию и теряем масштабируемость. Потому что лог в Binary Log пишется синхронно, и Group Binary Log Commit это решает.
Грустно, что приходится так делать из-за разделения Storage Engine внизу, репликация наверху. С этим все плохо. В MySQL 5.6 и 5.7 эта проблема решена есть Group Binary Log Commit, и мастер теперь не отстает. Теперь это пытаются использовать для параллелизма репликации, чтобы на слэйве запросы из одной группы запустить параллельно. Тут я написал, что из этого нужно крутить:
![](../../../meta/files/images/Pasted%20image%2020240528090205.png)
## Параллельная репликация
Сценарий ([Estimating potential for MySQL 5.7 parallel replication](https://www.percona.com/blog/estimating-potential-for-mysql-5-7-parallel-replication/)):
- 1 мастер, 3 слейва
- первый реплицирует в 1 поток
- второй в 20 потоков
- третий в 100 потоков
- вставка в 25 различных таблиц внутри одной базы в 100 потоков
![](../../../meta/files/images/Pasted%20image%2020240606094633.png)
Полезные опции:
- sysvar_replica_parallel_workers - количество потоков
- sysvar_replica_parallel_type
- DATABASE - транзакции применяются параллельно, если они обновляют разные БД
- LOGICAL_CLOCK - транзакции применяются параллельно на реплике на основе timestamp
## Отставание реплики
- [Отставание реплики БД](../../architecture/highload/Отставание%20реплики%20БД.md)
Диагностировать причину отставания реплики тяжело. Есть средство диагностики в MySQL, называется log медленных запросов. Вы можете его открыть, найти топ самых тяжелых запросов и исправить их. Но с репликацией это не работает. Нужно проводить статистический анализ считать статистику какие таблицы стали чаще использоваться. Вручную это сделать очень тяжело.
В MySQL 5.6 / 5.7 появилась SLAVE PERFORMANCE SCHEMA, на базе которой такую диагностику провести проще. Мы обычно открываем лог коммитов в puppet и смотрим, что же мы выкатили в то время, когда репликация начала отставать. Иногда даже это не помогает, приходится ходить по всем разработчикам и спрашивать, что они сделали, они ли сломали репликацию. Это грустно, но с этим приходится жить.
***
## Мета информация
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
**Родитель**:: [[../../architecture/highload/Репликация БД|Репликация БД]]
**Источник**::
**Автор**::
**Создана**:: [[2024-05-28]]
### Дополнительные материалы
- [Как устроена MySQL-репликация / Андрей Аксенов (Sphinx) - YouTube](https://www.youtube.com/watch?v=lHFaZkJk2O0)
- [Асинхронная репликация без цензуры / HighLoad](https://highload.guide/blog/asynchronous-replication.html)
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
- [[Row Based Replication (RBR)]]
- [[Statement Based Replication (SBR)]]
- [[Mixed binlog format]]
<!-- SerializedQuery END -->