Улучшения бинарного журнала и репликации¶
Благодаря постоянному развитию в MyDB Сервер для MySQL вошли ряд улучшений, связанные с репликацией и обработкой бинарных журналов. Это привело к особенностям репликации, отличающим ее от MySQL.
Безопасность операторов с указанием LIMIT
¶
MySQL рассматривает все команды UPDATE/DELETE/INSERT ... SELECT
с указанием LIMIT
как небезопасные. Эти команды переключают режим бинарного журнала с режима statement-based
на row-based
, если binlog_format
установлен в MIXED
.
Вот почему:
-
Указание
LIMIT
безORDER BY
делает результат недетерминированным -
Одна и та же команда может затрагивать разные строки даннных на первичном сервере и на репликах
UPDATE table1 LIMIT 10 SET col1 = 'value';
DELETE FROM table1 LIMIT 5;
INSERT INTO table2 SELECT * FROM table1 LIMIT 3;
Чтобы сделать эти команды безопасными для statement-based
репликации, нужно сделать одно из следующих действий:
-
Убрать указание
LIMIT
-
Добавить указание
ORDER BY
, чтобы сделать результаты детерминированными
UPDATE table1 SET col1 = 'value' ORDER BY id LIMIT 10;
DELETE FROM table1 ORDER BY id LIMIT 5;
INSERT INTO table2 SELECT * FROM table1 ORDER BY id LIMIT 3;
Исключение составляет случай, когда указание LIMIT
используется с ORDER BY
по уникальному ключу — в этом случае команда становится детерминированной и безопасной для statement-based
репликации.
MyDB Сервер для MySQL более точен, он рассматривает такие команды как безопасные, если они содержат укахание ORDER BY PK
или условие WHERE
.
Улучшение производительности при обновлении положения журнала ретрансляции¶
MySQL всегда обновляет позицию журнала ретрансляции в настройках репликации с несколькими источниками независимо от того, была ли уже выполнены зафиксированная транзакция или нет. MyDB Сервер пропускает обновления позиции журнала ретрансляции для уже зарегистрированных GTID.
Детали позиции журнала ретрансляции¶
В частности, такие безусловные обновления позиции журнала ретрансляции вызывали дополнительные операции fsync в случае relay-log-info-repository=TABLE
и с большим количеством каналов, передающих такие дублирующие (уже выполненные) транзакции, ситуация становилась хуже пропорционально. Исправлена ошибка #1786 (MySQL #85141).
Улучшение производительности при обновлении источника и статуса соединения¶
Реплики, настроенные для обновления состояния источника и информации о соединении только при ротации файла журнала, не наблюдали ожидаемого снижения нагрузки. MySQL дополнительно обновлял эту информацию в случае наличия нескольких источников репликации, когда реплике приходилось пропустить уже выполненное событие GTID.
Конфигурация с master_info_repository=TABLE
и sync_master_info=0
заставляет реплику обновлять информацию о состоянии источника и соединения в специальной таблице только при ротации файлов журнала, а не после каждых sync_master_info
событий. Но эта функциональность не работала в конфигурациях репликации с несколькими источниками. Сигналы Heartbeat, отправляемые на реплику, чтобы пропустить события GTID, которые она уже выполнила, ранее оценивались как события ротации журнала ретрансляции и приводили к синхронизации таблицы mysql.slave_master_info
. Эта неточность могла привести к огромному (вплоть до 5 раз при некоторых настройках) увеличению нагрузки на запись на реплике до того, как проблема была исправлена в Percona Server for MySQL. Исправлена ошибка #1812 (MySQL #85158).
Запись команд FLUSH
в бинарный журнал¶
Команды FLUSH
, такие как FLUSH SLOW LOGS
, не записываются в бинарный журнал, если системная переменная binlog_skip_flush_commands
установлена в ON.
Кроме того, были реализованы следующие изменения в поведении режимов read_only
и super_read_only
:
-
Когда для
read_only
установлено значение ON, любая командаFLUSH ...
, выполняемая обычным пользователем (без привилегииSUPER
), не записывается в бинарный журнал независимо от значения переменнойbinlog_skip_flush_commands
. -
Когда для параметра
super_read_only
установлено значение ON, любая командаFLUSH ...
, выполняемая любым пользователем (даже обладающим привилегиейSUPER
), не записывается в бинарный журнал независимо от значения переменнойbinlog_skip_flush_commands
.
Попытка запустить команду FLUSH
без привилегий SUPER
или RELOAD
приводит к ошибке ER_SPECIFIC_ACCESS_DENIED_ERROR
независимо от значения переменной binlog_skip_flush_commands
.
binlog_skip_flush_commands
¶
Свойство | Значение |
---|---|
Командная строка | Да |
Конфигурационный файл | Да |
Область видимости | Глобальная |
Динамическая | Да |
По умолчанию | OFF |
Когда для binlog_skip_flush_commands
установлено значение ON, команды FLUSH ...
не записываются в бинарный журнал.
Установка binlog_skip_flush_commands
не влияет на следующие команды, потому что они не записываются в бинарный журналЖ
• `FLUSH LOGS`
• `FLUSH BINARY LOGS`
• `FLUSH TABLES WITH READ LOCK`
• `FLUSH TABLES ... FOR EXPORT`
Команда FLUSH
не записывается в бинарный журнал и игнорирует значение binlog_skip_flush_commands
, когда она запускается с ключевым словом NO_WRITE_TO_BINLOG
(или его синонимом LOCAL
).
Сохранение комментариев в командах DDL¶
Когда вы выполняете команды DDL, например DROP TABLE
, сервер выполняет следующие действия в отношении бинарного журнала:
Действие | Описание |
---|---|
Удаляет комментарии | Сервер удаляет любые комментарии в изначальной команде. Например, если вы используете DROP TABLE my_table /* This is a comment */; , в бинарном журнале не сохраняется комментарий. |
Добавляет кавычки | Сервер добавляет кавычки вокруг имени таблицы. То есть, если вы запускаете DROP TABLE my_table; , он записывает в журнал DROP TABLE "my_table"; . |
Эти действия упрощают формат журналирования, но иногда вам нужен изначальный формат.
binlog_ddl_skip_rewrite¶
Свойство | Значение |
---|---|
Командная строка | Да |
Конфигурационный файл | Да |
Область видимости | Глобальная |
Динамическая | Да |
По умолчанию | OFF |
Если переменная выключена (по умолчанию), сервер удаляет комментарии и добавляет кавычки.
Если переменная включена, все DDL команды DROP TABLE
, затрагивающие одну таблицу, записываются в бинарный журнал в следующем виде:
• Комментарии сохраняются, то есть, любые заметки, которые вы добавляете в команду, остаются в бинарном журнале.
• Добавляются кавычки.
Вы можете включать binlog_ddl_skip_rewrite
на лету:
-- Проверяем текущее значение
SHOW VARIABLES LIKE 'binlog_ddl_skip_rewrite';
-- Включить переменную
SET GLOBAL binlog_ddl_skip_rewrite = ON;
-- Выключить переменную
SET GLOBAL binlog_ddl_skip_rewrite = OFF;
Вы можете включить её на постоянной основе, добавив её в конфигурационный файл
[mysqld]
binlog_ddl_skip_rewrite = ON
После добавления в конфигурационный файл перезапустите сервис MySQL.
DDL команды DROP TABLE
с несколькими таблицами не поддерживаются и возвращают ошибку.
SET binlog_ddl_skip_rewrite = ON;
/*comment at start*/DROP TABLE t /*comment at end*/;
Пользовательские функции бинарного журнала¶
Чтобы реализовать восстановление на определенный момент времени (point in time recovery), мы добавили binlog_utils_udf
. Включены следующие определяемые пользователем функции:
Имя | Возвращает | Описание |
---|---|---|
get_binlog_by_gtid() | Имя файла бинлога в виде строки | Возвращает имя файла бинлога, содержащего указанный GTID |
get_last_gtid_from_binlog() | GTID в виде строки | Возвращает последний GTID в указанном бинлоге |
get_gtid_set_by_binlog() | Набор GTID в виде строки | Возвращает все GTID в указанном бинлоге |
get_binlog_by_gtid_set() | Имя файла бинлога в виде строки | Возвращает имя файла бинлога, который содержит хотя бы один GTID из указанного набора |
get_first_record_timestamp_by_binlog() | Временную метку в виде целого числа | Возвращает временную метку первого события в указанном бинлоге |
get_last_record_timestamp_by_binlog() | Временную метку в виде целого числа | Возвращает временную метку последнего события в указанном бинлоге |
Все функции, возвращающие временные метки, возвращают свои значения в формате UNIX-времени с точностью до микросекунды. Другими словами, они представляют собой количество микросекунд, прошедших с 1 января 1970 года.
Все функции, принимающие имя бинарного журнала в качестве параметра, принимают только короткие имена без компонента пути. Если во входных данных обнаружен разделитель пути (/
), возвращается ошибка. Это требуется для ограничения путей, из которых можно читать бинарные журналы. Они всегда считываются из текущего каталога для бинарных журналов (системная переменная @@log_bin_basename).
Все функции, возвращающие имена файлов бинарного журнала, возвращают имя в краткой форме, без компонента пути.
Основной синтаксис get_binlog_by_gtid()
следующий:
* get_binlog_by_gtid(string) [AS] alias
Использование: SELECT get_binlog_by_gtid(string) [AS] alias
Пример использования команды get_binlog_gtid
:
CREATE FUNCTION get_binlog_by_gtid RETURNS STRING SONAME 'binlog_utils_udf.so';
SELECT get_binlog_by_gtid("F6F54186-8495-47B3-8D9F-011DDB1B65B3:1") AS result;
Ожидаемый результат
+--------------+
| result |
+==============+
| binlog.00001 |
+--------------+
DROP FUNCTION get_binlog_by_gtid;
Основной синтаксис get_last_gtid_from_binlog()
следующий:
* get_last_gtid_from_binlog(string) [AS] alias
Использование: SELECT get_last_gtid_from_binlog(string) [AS] alias
Например использования команды get_last_gtid_from_binlog
:
CREATE FUNCTION get_last_gtid_from_binlog RETURNS STRING SONAME 'binlog_utils_udf.so';
SELECT get_last_gtid_from_binlog("binlog.00001") AS result;
Ожидаемый результат
+-----------------------------------------+
| result |
+=========================================+
| F6F54186-8495-47B3-8D9F-011DDB1B65B3:10 |
+-----------------------------------------+
DROP FUNCTION get_last_gtid_from_binlog;
Основной синтаксис get_gtid_set_by_binlog()
следующий:
* get_gtid_set_by_binlog(string) [AS] alias
Использование: SELECT get_gtid_set_by_binlog(string) [AS] alias
Например использование команды get_gtid_set_by_binlog
:
CREATE FUNCTION get_gtid_set_by_binlog RETURNS STRING SONAME 'binlog_utils_udf.so';
SELECT get_gtid_set_by_binlog("binlog.00001") AS result;
Ожидаемый результат
+-------------------------+
| result |
+=========================+
| 11ea-b9a7:7,11ea-b9a7:8 |
+-------------------------+
DROP FUNCTION get_gtid_set_by_binlog;
Основной синтаксис get_binlog_by_gtid_set()
следующий:
* get_binlog_by_gtid_set(string) [AS] alias
Использование: SELECT get_binlog_by_gtid_set(string) [AS] alias
Пример использования команды get_binlog_by_gtid_set
:
CREATE FUNCTION get_binlog_by_gtid_set RETURNS STRING SONAME 'binlog_utils_udf.so';
SELECT get_binlog_by_gtid_set("11ea-b9a7:7,11ea-b9a7:8") AS result;
Ожидаемый результат
+---------------------------------------------------------------+
| result |
+===============================================================+
| bin.000003 |
+---------------------------------------------------------------+
DROP FUNCTION get_binlog_by_gtid_set;
Основной синтаксис get_first_record_timestamp_by_binlog()
следующий:
* get_first_record_timestamp_by_binlog(TIMESTAMP) [AS] alias
Использование: SELECT get_first_record_timestamp_by_binlog(TIMESTAMP) [AS] alias
Пример использования команды get_first_record_timestamp_by_binlog
:
CREATE FUNCTION get_first_record_timestamp_by_binlog RETURNS INTEGER SONAME 'binlog_utils_udf.so';
SELECT FROM_UNIXTIME(get_first_record_timestamp_by_binlog("bin.00003") DIV 1000000) AS result;
Ожидаемый результат
+---------------------+
| result |
+=====================+
| 2020-12-03 09:10:40 |
+---------------------+
DROP FUNCTION get_first_record_timestamp_by_binlog;
Основной синтаксис get_last_record_timestamp_by_binlog()
следующий:
* get_last_record_timestamp_by_binlog(TIMESTAMP) [AS] alias
Использование: SELECT get_last_record_timestamp_by_binlog(TIMESTAMP) [AS] alias
Пример использования команды get_last_record_timestamp_by_binlog
:
CREATE FUNCTION get_last_record_timestamp_by_binlog RETURNS INTEGER SONAME 'binlog_utils_udf.so';
SELECT FROM_UNIXTIME(get_last_record_timestamp_by_binlog("bin.00003") DIV 1000000) AS result;
Ожидаемый результат
+---------------------+
| result |
+=====================+
| 2020-12-04 04:18:56 |
+---------------------+
DROP FUNCTION get_last_record_timestamp_by_binlog;
Ограничения¶
Для следующих переменных не присваивайте значения с одним или несколькими символами точки (.
):
Значение с использованием точки (.
) обрабатывается по-разному в MySQL и Percona XtraBackup и может привести к непредсказуемому поведению.