Spec-Zone.ru › MySQL 5.7

16.1.3.2 Жизненный цикл GTID

Жизненный цикл GTID состоит из следующих шагов:

  1. Транзакция выполняется и подтверждается на сервере источника репликации. Эту клиентскую транзакцию присваивают GTID, составленный из UUID источника и наименьшего ненулевого номера последовательности транзакций, ещё не используемого на этом сервере. GTID записывается в двоичный журнал источника (непосредственно перед самой транзакцией в журнале). Если клиентская транзакция не записывается в двоичный журнал (например, потому что транзакция была отфильтрована или транзакция была только для чтения), ей не присваивается GTID.

  2. Если транзакции был присвоен GTID, GTID сохраняется атомарно в момент подтверждения путём записи его в двоичный журнал в начале транзакции (как Gtid_log_event). При каждом вращении двоичного журнала или выключении сервера сервер записывает GTID для всех транзакций, которые были записаны в предыдущий файл двоичного журнала, в таблицу mysql.gtid_executed.

  3. Если транзакции был присвоен GTID, GTID делается внешним неатомарно (вскоре после подтверждения транзакции) путём добавления его в набор GTID в системной переменной gtid_executed (@@GLOBAL.gtid_executed). Этот набор GTID содержит представление набора всех подтверждённых транзакций GTID, и он используется в репликации в качестве маркера, представляющего состояние сервера. При включённом двоичном журнале (как требуется для источника), набор GTID в системной переменной gtid_executed является полным записыванием применённых транзакций, но таблица mysql.gtid_executed не является, так как самая последняя история всё ещё находится в текущем файле двоичного журнала.

  4. После передачи данных двоичного журнала реплике и сохранения их в релейном журнале реплики (используя установленные механизмы для этого процесса, см. Раздел 16.2, «Реализация репликации» для подробностей), реплика читает GTID и устанавливает значение своей системной переменной gtid_next в качестве этого GTID. Это сообщает реплике, что следующая транзакция должна быть записана с помощью этого GTID. Важно отметить, что реплика устанавливает gtid_next в контексте сеанса.

  5. Реплика проверяет, не взял ли ещё ни один поток владение GTID в gtid_next для обработки транзакции. Сначала прочитав и проверив GTID реплицированной транзакции перед самой обработкой транзакции, реплика гарантирует, что на реплике ещё не была применена никакая предыдущая транзакция с этим GTID, а также, что никакой другой сеанс ещё не прочитал этот GTID, но ещё не подтвердил связанную транзакцию. Таким образом, если несколько клиентов пытаются применить одну и ту же транзакцию одновременно, сервер решает это, позволяя только одному из них выполнить её. Системная переменная gtid_owned (@@GLOBAL.gtid_owned) для реплики показывает каждый GTID, который в настоящее время используется, и идентификатор потока, которому он принадлежит. Если GTID уже был использован, ошибка не генерируется, и используется функция автоматического пропуска для игнорирования транзакции.

  6. Если GTID не был использован, реплика применяет реплицированную транзакцию. Поскольку gtid_next уже установлено в GTID, назначенный источником, реплика не пытается сгенерировать новый GTID для этой транзакции, а вместо этого использует GTID, хранящийся в gtid_next.

  7. Если на реплике включён двоичный журнал, GTID сохраняется атомарно в момент подтверждения, записывая его в двоичный журнал в начале транзакции (как Gtid_log_event). При каждом вращении двоичного журнала или выключении сервера сервер записывает GTID для всех транзакций, которые были записаны в предыдущий файл двоичного журнала, в таблицу mysql.gtid_executed.

  8. Если на реплике двоичный журнал отключён, GTID сохраняется атомарно путём прямой записи в таблицу mysql.gtid_executed. MySQL добавляет оператор в транзакцию для вставки GTID в таблицу. В этой ситуации таблица mysql.gtid_executed является полным записыванием применённых на реплике транзакций. Обратите внимание, что в MySQL 5.7 операция вставки GTID в таблицу атомарна для DML-операторов, но не для DDL-операторов, поэтому, если сервер неожиданно завершит работу после транзакции, включающей DDL-операторы, состояние GTID может стать несогласованным. С MySQL 8.0 операция атомарна как для DDL-, так и для DML-операторов.

  9. Вскоре после подтверждения реплицированной транзакции на реплике GTID делается внешним неатомарно путём добавления его в набор GTID в системной переменной gtid_executed (@@GLOBAL.gtid_executed) для реплики. Как и для источника, этот набор GTID содержит представление набора всех подтверждённых транзакций GTID. Если на реплике двоичный журнал отключён, таблица mysql.gtid_executed также является полным записыванием применённых на реплике транзакций. Если на реплике включён двоичный журнал, что означает, что некоторые GTID записываются только в двоичном журнале, набор GTID в системной переменной gtid_executed является единственным полным записыванием.

Клиентские транзакции, полностью отфильтрованные на источнике, не получают GTID, поэтому они не добавляются в набор транзакций в системной переменной gtid_executed или в таблицу mysql.gtid_executed. Однако GTID реплицированных транзакций, полностью отфильтрованных на реплике, сохраняются. Если на реплике включён двоичный журнал, отфильтрованная транзакция записывается в двоичный журнал как Gtid_log_event, за которым следует пустая транзакция, содержащая только операторы BEGIN и COMMIT. Если двоичный журнал отключён, GTID отфильтрованной транзакции записывается в таблицу mysql.gtid_executed. Сохранение GTID для отфильтрованных транзакций гарантирует, что таблицу mysql.gtid_executed и набор GTID в системной переменной gtid_executed можно сжать. Это также гарантирует, что отфильтрованные транзакции не будут извлекаться повторно, если реплика подключается к источнику, как объяснено в Разделе 16.1.3.3, «Автоматическое позиционирование GTID».

На многопоточной реплике (с slave_parallel_workers > 0) транзакции могут применяться параллельно, поэтому реплицированные транзакции могут подтверждаться в произвольном порядке (если slave_preserve_commit_order=1 не установлено). В этом случае набор GTID в системной переменной gtid_executed содержит несколько диапазонов GTID с разрывами между ними. (На источнике или однопоточной реплике GTID увеличиваются монотонно без разрывов между числами.) Разрывы на многопоточных репликах возникают только среди самых последних применённых транзакций и заполняются по мере продвижения репликации. Когда реплицирующие потоки останавливаются корректно с помощью оператора STOP SLAVE, текущие транзакции применяются, чтобы разрывы заполнились. В случае сбоя, такого как отказ сервера или использование оператора KILL для остановки реплицирующих потоков, разрывы могут остаться.

Какие изменения присваиваются GTID?

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

Каждому изменению базы данных (DDL или DML), которое записывается в двоичный журнал, присваивается GTID. Это включает изменения, которые автоматически подтверждаются, и изменения, которые подтверждаются с помощью операторов BEGIN и COMMIT или START TRANSACTION. GTID также присваивается при создании, изменении или удалении базы данных, а также при создании, изменении или удалении объекта базы данных, не являющегося таблицей, такого как процедура, функция, триггер, событие, представление, пользователь, роль или грант.

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

Когда таблица автоматически удаляется сгенерированным оператором в двоичном журнале, оператору присваивается GTID. Временные таблицы удаляются автоматически, когда реплика начинает применять события от источника, который только что был запущен, а также при использовании репликации на основе операторов (binlog_format=STATEMENT) и когда сеанс пользователя, у которого открыты временные таблицы, отключается. Таблицы, использующие хранилище MEMORY, удаляются автоматически при первом обращении к ним после запуска сервера, поскольку строки могли быть потеряны во время завершения работы.

Если транзакция не записывается в двоичный журнал на исходном сервере, сервер не присваивает ей GTID. Это включает транзакции, которые были отменены, и транзакции, которые были выполнены при отключённой записи двоичного журнала на исходном сервере, глобально (с --skip-log-bin, указанным в конфигурации сервера) или для сеанса (SET @@SESSION.sql_log_bin = 0). Это также включает транзакции без действий, когда используется репликация на основе строк (binlog_format=ROW).

Транзакциям XA присваиваются отдельные GTID для фазы XA PREPARE транзакции и фазы XA COMMIT или XA ROLLBACK транзакции. XA-транзакции сохраняются подготовленными, чтобы пользователи могли их подтвердить или отменить в случае сбоя (что в топологии репликации может включать переход к другому серверу). Поэтому две части транзакции дублируются отдельно, поэтому они должны иметь свои собственные GTID, даже если бы транзакция без XA, которая была отменена, не имела бы GTID.

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

  • Вызывается хранимая процедура, которая подтверждает несколько транзакций. Для каждой транзакции, подтверждённой процедурой, генерируется один GTID.

  • Оператор многотабличного удаления DROP TABLE удаляет таблицы разных типов.

  • Оператор CREATE TABLE ... SELECT выполняется при использовании репликации на основе строк (binlog_format=ROW). Один GTID генерируется для действия CREATE TABLE, и один GTID генерируется для действий вставки строк.

Переменная системы gtid_next

По умолчанию для новых транзакций, подтверждённых в пользовательских сеансах, сервер автоматически генерирует и присваивает новый GTID. При применении транзакции на реплике сохраняется GTID с исходного сервера. Вы можете изменить это поведение, установив значение сеанса переменной системы gtid_next:

  • Когда gtid_next установлена на AUTOMATIC, что является значением по умолчанию, и транзакция подтверждена и записана в двоичный журнал, сервер автоматически генерирует и присваивает новый GTID. Если транзакция отменена или не записана в двоичный журнал по другой причине, сервер не генерирует и не присваивает GTID.

  • Если вы установите gtid_next на допустимый GTID (состоящий из UUID и номера последовательности транзакции, разделенных двоеточием), сервер присвоит этот GTID вашей транзакции. Этот GTID присваивается и добавляется в gtid_executed, даже если транзакция не записана в двоичный журнал или если транзакция пустая.

Обратите внимание, что после установки gtid_next на определённый GTID и транзакция была подтверждена или отменена, перед любым другим оператором должен быть выпущен явный оператор SET @@SESSION.gtid_next. Вы можете использовать это, чтобы вернуть значение GTID к AUTOMATIC, если вы не хотите присваивать больше GTID явно.

Когда потоки прикладных реплик применяют дублированные транзакции, они используют эту технику, явно устанавливая @@SESSION.gtid_next на GTID дублированной транзакции, как присвоено на исходном сервере. Это означает, что GTID с исходного сервера сохраняется, а не генерируется и присваивается новый GTID репликой. Это также означает, что GTID добавляется в gtid_executed на реплике, даже если ведение двоичного журнала или ведение журнала обновлений реплики отключено на реплике, или если транзакция является пустой операцией или отфильтрована на реплике.

Клиент может смоделировать дублированную транзакцию, установив @@SESSION.gtid_next на определённый GTID перед выполнением транзакции. Эта техника используется mysqlbinlog для генерации дампа двоичного журнала, который клиент может воспроизвести для сохранения GTID. Дублированная транзакция, смоделированная с помощью клиента, подтвержденная таким способом, полностью эквивалентна транзакции, подтвержденной с помощью потока реплики, и их невозможно отличить задним числом.

Переменная системы gtid_purged

Множество GTID в переменной системы gtid_purged (@@GLOBAL.gtid_purged) содержит GTID всех транзакций, которые были выполнены на сервере, но не существуют в любом файле бинарного журнала на сервере. gtid_purged является подмножеством gtid_executed. Следующие категории GTID находятся в gtid_purged:

  • GTID реплицированных транзакций, которые были выполнены при отключённой записи бинарного журнала на реплике.

  • GTID транзакций, которые были записаны в файл бинарного журнала, который теперь удалён.

  • GTID, которые были явно добавлены в множество операцией SET @@GLOBAL.gtid_purged.

Вы можете изменить значение gtid_purged, чтобы записать на сервере, что транзакции в определённом наборе GTID были применены, хотя они не существуют в любом бинарном журнале на сервере. При добавлении GTID в gtid_purged, они также добавляются в gtid_executed. Пример использования этого действия - когда вы восстанавливаете резервную копию одной или нескольких баз данных на сервере, но у вас нет соответствующих бинарных журналов, содержащих транзакции на сервере. В MySQL 5.7 вы можете изменить значение gtid_purged только тогда, когда gtid_executed (и, следовательно, gtid_purged) пусто. Подробности см. в описании gtid_purged.

Наборы GTID в переменных системы gtid_executed и gtid_purged инициализируются при запуске сервера. Каждый файл бинарного журнала начинается с события Previous_gtids_log_event, которое содержит множество GTID во всех предыдущих файлах бинарного журнала (составленное из GTID в предыдущем файле Previous_gtids_log_event и GTID каждого Gtid_log_event в предыдущем файле). Содержимое Previous_gtids_log_event в старейшем и самом последнем файлах бинарного журнала используется для вычисления множеств gtid_executed и gtid_purged при запуске сервера:

  • gtid_executed вычисляется как объединение GTID в Previous_gtids_log_event в самом последнем файле бинарного журнала, GTID транзакций в этом файле бинарного журнала и GTID, хранящиеся в таблице mysql.gtid_executed. Этот набор GTID содержит все GTID, которые были использованы (или явно добавлены в gtid_purged) на сервере, независимо от того, находятся ли они в данный момент в файле бинарного журнала на сервере. Он не включает GTID транзакций, которые в данный момент обрабатываются на сервере (@@GLOBAL.gtid_owned).

  • gtid_purged вычисляется, сначала добавив GTID в Previous_gtids_log_event в последнем файле бинарного журнала и GTID транзакций в этом файле бинарного журнала. Этот шаг даёт множество GTID, которые в настоящий момент или когда-либо ранее были записаны в бинарном журнале на сервере (gtids_in_binlog). Затем GTID в Previous_gtids_log_event в старейшем файле бинарного журнала вычитаются из gtids_in_binlog. Этот шаг даёт множество GTID, которые в настоящий момент записаны в бинарном журнале на сервере (gtids_in_binlog_not_purged). Наконец, gtids_in_binlog_not_purged вычитается из gtid_executed. Результат — множество GTID, которые были использованы на сервере, но в настоящий момент не записаны в файл бинарного журнала на сервере, и этот результат используется для инициализации gtid_purged.

Если бинарные журналы от MySQL 5.7.7 или более ранних версий участвуют в этих вычислениях, возможно, что для gtid_executed и gtid_purged будут вычислены неправильные множества GTID, и они останутся неправильными даже если сервер будет перезапущен позже. Подробности см. в описании переменной системы binlog_gtid_simple_recovery, которая управляет тем, как бинарные журналы итерируются для вычисления множеств GTID. Если одна из описанных ситуаций применима к серверу, задайте binlog_gtid_simple_recovery=FALSE в файле конфигурации сервера перед его запуском. Это задание заставляет сервер итерировать все файлы бинарного журнала (а не только самые новые и старые), чтобы найти, где появляются события GTID. Этот процесс может занять много времени, если у сервера большое количество файлов бинарного журнала без событий GTID.

Сброс истории выполнения GTID

Если вам нужно сбросить историю выполнения GTID на сервере, используйте оператор RESET MASTER. Например, вам может потребоваться сделать это после проведения тестовых запросов для проверки настройки репликации на новых серверах с поддержкой GTID или при подключении нового сервера к группе репликации, но он содержит некоторые нежелательные локальные транзакции, которые не принимаются группой репликации.

Предупреждение

Используйте RESET MASTER с осторожностью, чтобы избежать потери желаемой истории выполнения GTID и файлов бинарного журнала.

Перед выполнением RESET MASTER, убедитесь, что у вас есть резервные копии файлов бинарного журнала и файла индекса бинарного журнала сервера (если таковой имеется), и получите и сохраните набор GTID, хранящийся в глобальном значении переменной системы gtid_executed (например, выполнив оператор SELECT @@GLOBAL.gtid_executed и сохранив результаты). Если вы удаляете нежелательные транзакции из этого множества GTID, используйте mysqlbinlog для проверки содержимого транзакций, чтобы убедиться, что они не имеют значения, не содержат данных, которые необходимо сохранить или реплицировать, и не привели к изменениям данных на сервере.

При выполнении RESET MASTER выполняются следующие операции сброса:

  • Значение переменной системы gtid_purged устанавливается в пустую строку ('').

  • Глобальное значение (но не сессионное значение) переменной системы gtid_executed устанавливается в пустую строку.

  • Таблица mysql.gtid_executed очищается (см. mysql.gtid_executed Table).

  • Если на сервере включена запись бинарного журнала, существующие файлы бинарного журнала удаляются, а файл индекса бинарного журнала очищается.

Обратите внимание, что RESET MASTER является методом для сброса истории выполнения GTID, даже если сервер является репликой, где запись бинарного журнала отключена. RESET SLAVE не влияет на историю выполнения GTID.

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/replication-gtids-lifecycle.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API