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.