19.1.3.2 Жизненный цикл GTID
Жизненный цикл GTID состоит из следующих шагов:
Транзакция выполняется и подтверждается на источнике. Эта клиентская транзакция получает GTID, состоящий из UUID источника и наименьшего ненулевого номера последовательности транзакции, еще не используемого на этом сервере. GTID записывается в бинарный журнал источника (непосредственно перед самой транзакцией в журнале). Если клиентская транзакция не записывается в бинарный журнал (например, потому что транзакция была отфильтрована или транзакция была только для чтения), ей не назначается GTID.
Если для транзакции был назначен GTID, GTID сохраняется атомарно во время подтверждения, записывая его в бинарный журнал в начале транзакции (как
Gtid_log_event). Всякий раз, когда бинарный журнал вращается или сервер выключается, сервер записывает GTID для всех транзакций, которые были записаны в предыдущий файл бинарного журнала, в таблицуmysql.gtid_executed.Если для транзакции был назначен GTID, GTID экстернализируется неатомарно (вскоре после подтверждения транзакции), добавляя его в набор GTID в системной переменной
gtid_executed(@@GLOBAL.gtid_executed). Этот набор GTID содержит представление набора всех подтвержденных транзакций GTID и используется в репликации как маркер, представляющий состояние сервера. При включенном бинарном журнале (как требуется для источника), набор GTID в системной переменнойgtid_executedявляется полным записями примененных транзакций, но таблицаmysql.gtid_executedнет, потому что самая последняя история все еще находится в текущем файле бинарного журнала.После передачи данных бинарного журнала реплике и хранения их в релейном журнале реплики (используя установленные механизмы этого процесса, см. Раздел 19.2, «Реализация репликации» для получения подробностей), реплика считывает GTID и устанавливает значение своей системной переменной
gtid_nextкак этот GTID. Это сообщает реплике, что следующая транзакция должна быть записана с использованием этого GTID. Важно отметить, что реплика устанавливаетgtid_nextв контексте сеанса.Реплика проверяет, не взял ли ни один поток владение GTID в
gtid_next, чтобы обработать транзакцию. Считывая и проверяя GTID реплицированной транзакции перед самой обработкой транзакции, реплика гарантирует, что ни одна предыдущая транзакция с этим GTID не была применена на реплике, а также что ни один другой сеанс не прочитал этот GTID, но еще не подтвердил связанную транзакцию. Таким образом, если несколько клиентов пытаются применить одну и ту же транзакцию одновременно, сервер разрешает это, позволяя только одному из них выполнить ее. Системная переменнаяgtid_owned(@@GLOBAL.gtid_owned) для реплики отображает каждый GTID, который в настоящее время используется, и идентификатор потока, которому он принадлежит. Если GTID уже был использован, ошибка не генерируется, и используется функция автоматического пропуска для игнорирования транзакции.Если GTID не использовался, реплика применяет реплицированную транзакцию. Поскольку
gtid_nextустановлено на GTID, уже назначенный источником, реплика не пытается сгенерировать новый GTID для этой транзакции, а вместо этого использует GTID, хранящийся вgtid_next.Если бинарный журнал включен на реплике, GTID сохраняется атомарно во время подтверждения, записывая его в бинарный журнал в начале транзакции (как
Gtid_log_event). Всякий раз, когда бинарный журнал вращается или сервер выключается, сервер записывает GTID для всех транзакций, которые были записаны в предыдущий файл бинарного журнала, в таблицуmysql.gtid_executed.Если бинарный журнал отключен на реплике, GTID сохраняется атомарно, записывая его непосредственно в таблицу
mysql.gtid_executed. MySQL добавляет утверждение в транзакцию для вставки GTID в таблицу. Эта операция является атомарной как для DDL, так и для DML утверждений. В этой ситуации таблицаmysql.gtid_executedявляется полным записями примененных на реплике транзакций.Вскоре после подтверждения реплицированной транзакции на реплике 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 могут быть сжаты. Это также гарантирует, что отфильтрованные транзакции не будут снова извлекаться, если реплика снова подключится к источнику, как описано в Разделе 19.1.3.3, «Автопозиционирование GTID».
На многопотоковой реплике (с replica_parallel_workers > 0) транзакции могут применяться параллельно, поэтому реплицированные транзакции могут подтверждаться в произвольном порядке (если не replica_preserve_commit_order =
1). В этом случае набор GTID в системной переменной gtid_executed содержит несколько диапазонов GTID с разрывами между ними. (На источнике или однопотоковой реплике есть монотонно возрастающие GTID без разрывов между числами.) Разрывы на многопотоковых репликах возникают только среди недавно примененных транзакций и заполняются по мере прогресса репликации. При аккуратной остановке потоков репликации с помощью утверждения STOP
REPLICA текущие транзакции применяются таким образом, что разрывы заполняются. В случае завершения работы, таком как отказ сервера или использование утверждения 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для нескольких таблиц удаляет таблицы различных типов. Несколько GTID могут быть сгенерированы, если какие-либо таблицы используют хранилища, которые не поддерживают атомарные DDL, или если какие-либо таблицы являются временными таблицами.Выполняется инструкция
CREATE TABLE ... SELECT, когда используется репликация на основе строк (binlog_format=ROW). Один GTID генерируется для действияCREATE TABLE, и один GTID генерируется для действий вставки строк.
Переменная системы gtid_next
По умолчанию для новых транзакций, подтвержденных в пользовательских сессиях, сервер автоматически генерирует и назначает новый GTID. При применении транзакции на реплике GTID с сервера-источника сохраняется. Вы можете изменить это поведение, изменив значение переменной сессии gtid_next:
Когда
gtid_nextустановлено в значениеAUTOMATIC(по умолчанию), при подтверждении транзакции и записи ее в двоичный журнал, сервер автоматически генерирует и назначает новый GTID. Если транзакция отменена или не записана в двоичный журнал по какой-либо другой причине, сервер не генерирует и не назначает GTID.Если вы установите
gtid_nextв значениеAUTOMATIC:, каждому новому выполнению транзакции будет назначен новый GTID, включающий указанную метку.TAGЕсли вы установите
gtid_nextв действительный GTID (состоящий из UUID, необязательной метки и номера последовательности транзакции, разделенных двоеточием), сервер назначит этот GTID вашей транзакции. Этот GTID назначается и добавляется вgtid_executed, даже если транзакция не записана в двоичный журнал или если транзакция пустая.
Обратите внимание, что после установки gtid_next на определенный GTID (в формате или UUID:NUMBER), и после подтверждения или отмены транзакции, необходимо выполнить явную инструкцию UUID:TAG:NUMBERSET @@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_purged содержатся следующие категории GTID:
GTID реплицированных транзакций, которые были завершены с отключённой записью в двоичный журнал на реплике.
GTID транзакций, которые были записаны в файл двоичного журнала, который теперь удалён.
GTID, которые были явно добавлены в множество оператором
SET @@GLOBAL.gtid_purged.
Вы можете изменить значение gtid_purged, чтобы записать на сервере, что транзакции в определённом наборе GTID были применены, хотя они не существуют ни в одном двоичном журнале на сервере. При добавлении GTID в gtid_purged, они также добавляются в gtid_executed. Пример использования этого действия — восстановление резервной копии одной или нескольких баз данных на сервере, но без соответствующих двоичных журналов, содержащих транзакции на сервере. Вы также можете выбрать, заменить ли весь набор GTID в gtid_purged заданным набором GTID или добавить заданный набор GTID к GTID, уже имеющимся в 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). Затем изgtids_in_binlogвычитаются GTID вPrevious_gtids_log_eventв самом старом файле двоичного журнала. Этот шаг даёт множество GTID, которые в настоящий момент записаны в двоичном журнале на сервере (gtids_in_binlog_not_purged). Наконец,gtids_in_binlog_not_purgedвычитается изgtid_executed. Результатом является множество GTID, которые использовались на сервере, но в данный момент не записаны в файле двоичного журнала на сервере, и этот результат используется для инициализацииgtid_purged.
Сброс истории выполнения GTID
Если необходимо сбросить историю выполнения GTID на сервере, используйте оператор RESET BINARY LOGS AND GTIDS. Это может потребоваться после проведения тестовых запросов для проверки конфигурации репликации на новых серверах, поддерживающих GTID, или при подключении нового сервера к группе репликации, но он содержит нежелательные локальные транзакции, которые не принимаются группой репликации.
Используйте RESET BINARY LOGS AND GTIDS с осторожностью, чтобы избежать потери желаемой истории выполнения GTID и файлов двоичного журнала.
Перед выполнением RESET BINARY LOGS AND
GTIDS убедитесь, что у вас есть резервные копии файлов двоичного журнала и файла индекса двоичного журнала сервера, если таковые имеются, а также получите и сохраните множество GTID, хранящихся в глобальном значении переменной системы gtid_executed (например, выполнив оператор SELECT
@@GLOBAL.gtid_executed и сохранив результаты). Если вы удаляете нежелательные транзакции из этого множества GTID, используйте mysqlbinlog для проверки содержимого транзакций, чтобы убедиться, что они не имеют значения, не содержат данных, которые необходимо сохранить или реплицировать, и не привели к изменениям данных на сервере.
При выполнении RESET BINARY LOGS AND
GTIDS выполняются следующие операции сброса:
Значение переменной системы
gtid_purgedустанавливается в пустую строку ('').Глобальное значение (но не сессионное) переменной системы
gtid_executedустанавливается в пустую строку.Таблица
mysql.gtid_executedочищается (см. mysql.gtid_executed Table).Если на сервере включена запись в двоичный журнал, существующие файлы двоичного журнала удаляются, а файл индекса двоичного журнала очищается.
Обратите внимание, что RESET BINARY LOGS AND
GTIDS является методом сброса истории выполнения GTID, даже если сервер является репликой, где запись в двоичный журнал отключена. RESET REPLICA не влияет на историю выполнения GTID.
© 2025 Oracle
Licensed under the GPLv2 License.