MariaDB
 sql >> база данни >  >> RDS >> MariaDB

Използване на MariaDB Flashback на MySQL сървър

MariaDB представи много готина функция, наречена Flashback. Flashback е функция, която позволява на екземпляри, бази данни или таблици да бъдат върнати към стара моментна снимка. Традиционно, за да се извърши възстановяване в момента (PITR), човек ще възстанови база данни от резервно копие и ще възпроизведе двоичните регистрационни файлове, за да превърти напред състоянието на базата данни в определено време или позиция.

С Flashback базата данни може да бъде върната назад към момент от време в миналото, което е много по-бързо, ако просто искаме да видим миналото, което току-що се е случило неотдавна. Понякога използването на ретроспекция може да е неефективно, ако искате да видите много стара моментна снимка на вашите данни спрямо текущата дата и час. Възстановяването от забавено подчинено устройство или от резервно копие плюс повторно възпроизвеждане на двоичния дневник може да са по-добрите опции.

Тази функция е достъпна само в клиентския пакет MariaDB, но това не означава, че не можем да я използваме с нашите MySQL сървъри. Тази публикация в блога показва как можем да използваме тази невероятна функция на MySQL сървър.

Изисквания на MariaDB Flashback

За тези, които искат да използват функцията за ретроспекция на MariaDB върху MySQL, можем основно да направим следното:

  1. Активирайте двоичния дневник със следната настройка:
    1. binlog_format =ROW (по подразбиране от MySQL 5.7.7).
    2. binlog_row_image =FULL (по подразбиране от MySQL 5.6).
  2. Използвайте помощната програма msqlbinlog от всяка инсталация на MariaDB 10.2.4 и по-нова версия.
  3. Flashback в момента се поддържа само чрез DML изрази (INSERT, DELETE, UPDATE). Предстояща версия на MariaDB ще добави поддръжка за ретроспекция върху DDL изрази (DROP, TRUNCATE, ALTER и т.н.) чрез копиране или преместване на текущата таблица в запазена и скрита база данни и след това копиране или преместване назад, когато се използва ретроспекция.

Ретроспекцията се постига чрез използване на съществуващата поддръжка за двоични дневници с пълен формат на изображение, като по този начин поддържа всички механизми за съхранение. Имайте предвид, че събитията с ретроспекция ще бъдат съхранени в паметта. Затова трябва да се уверите, че вашият сървър има достатъчно памет за тази функция.

Как работи MariaDB Flashback?

Помощната програма mysqlbinlog на MariaDB се предлага с две допълнителни опции за тази цел:

  • -B, --flashback – Функцията Flashback може да върне вашите ангажирани данни до специална времева точка.
  • -T, --table=[име] – Списък на записи само за тази таблица (само локален дневник).

Сравнявайки изхода на mysqlbinlog със и без флага --flashback, можем лесно да разберем как работи. Помислете, че следният оператор се изпълнява на сървър на MariaDB:

MariaDB> DELETE FROM sbtest.sbtest1 WHERE id = 1;

Без флаг за ретроспекция ще видим действителното събитие DELETE binlog:

$ mysqlbinlog -vv \
--start-datetime="$(date '+%F %T' -d 'now - 10 minutes')" \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000003

...
# at 453196541
#200227 12:58:18 server id 37001  end_log_pos 453196766 CRC32 0xdaa248ed Delete_rows: table id 238 flags: STMT_END_F

BINLOG '
6rxXXhOJkAAAQwAAAP06AxsAAO4AAAAAAAEABnNidGVzdAAHc2J0ZXN0MQAEAwP+/gTu4P7wAAEB
AAID/P8AFuAQfA==
6rxXXiCJkAAA4QAAAN47AxsAAO4AAAAAAAEAAgAE/wABAAAAVJ4HAHcAODM4Njg2NDE5MTItMjg3
NzM5NzI4MzctNjA3MzYxMjA0ODYtNzUxNjI2NTk5MDYtMjc1NjM1MjY0OTQtMjAzODE4ODc0MDQt
NDE1NzY0MjIyNDEtOTM0MjY3OTM5NjQtNTY0MDUwNjUxMDItMzM1MTg0MzIzMzA7Njc4NDc5Njcz
NzctNDgwMDA5NjMzMjItNjI2MDQ3ODUzMDEtOTE0MTU0OTE4OTgtOTY5MjY1MjAyOTHtSKLa
'/*!*/;

### DELETE FROM `sbtest`.`sbtest1`
### WHERE
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2=499284 /* INT meta=0 nullable=0 is_null=0 */
###   @3='83868641912-28773972837-60736120486-75162659906-27563526494-20381887404-41576422241-93426793964-56405065102-33518432330' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='67847967377-48000963322-62604785301-91415491898-96926520291' /* STRING(240) meta=65264 nullable=0 is_null=0 */
...

Като разширим горната команда mysqlbinlog с --flashback, можем да видим, че събитието DELETE се преобразува в събитие INSERT и подобно на съответните клаузи WHERE и SET:

$ mysqlbinlog -vv \
--start-datetime="$(date '+%F %T' -d 'now - 10 minutes')" \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000003 \
--flashback

...
BINLOG '
6rxXXhOJkAAAQwAAAP06AxsAAO4AAAAAAAEABnNidGVzdAAHc2J0ZXN0MQAEAwP+/gTu4P7wAAEB
AAID/P8AFuAQfA==
6rxXXh6JkAAA4QAAAN47AxsAAO4AAAAAAAEAAgAE/wABAAAAVJ4HAHcAODM4Njg2NDE5MTItMjg3
NzM5NzI4MzctNjA3MzYxMjA0ODYtNzUxNjI2NTk5MDYtMjc1NjM1MjY0OTQtMjAzODE4ODc0MDQt
NDE1NzY0MjIyNDEtOTM0MjY3OTM5NjQtNTY0MDUwNjUxMDItMzM1MTg0MzIzMzA7Njc4NDc5Njcz
NzctNDgwMDA5NjMzMjItNjI2MDQ3ODUzMDEtOTE0MTU0OTE4OTgtOTY5MjY1MjAyOTHtSKLa
'/*!*/;

### INSERT INTO `sbtest`.`sbtest1`
### SET
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2=499284 /* INT meta=0 nullable=0 is_null=0 */
###   @3='83868641912-28773972837-60736120486-75162659906-27563526494-20381887404-41576422241-93426793964-56405065102-33518432330' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='67847967377-48000963322-62604785301-91415491898-96926520291' /* STRING(240) meta=65264 nullable=0 is_null=0 */
...

При репликация, базирана на ред (binlog_format=ROW), всяко събитие за промяна на ред съдържа две изображения, изображение „преди“ (с изключение на INSERT), чиито колони се съпоставят при търсене на реда, който трябва да се актуализира, и изображение „след“ (с изключение на DELETE), съдържащо промените. С binlog_row_image=FULL, MariaDB регистрира пълни редове (тоест всички колони) както за изображенията преди, така и за след.

Следният пример показва двоични регистрационни събития за UPDATE. Помислете, че следният оператор се изпълнява на сървър на MariaDB:

MariaDB> UPDATE sbtest.sbtest1 SET k = 0 WHERE id = 5;

Когато разглеждаме събитието binlog за горното изявление, ще видим нещо подобно:

$ mysqlbinlog -vv \
--start-datetime="$(date '+%F %T' -d 'now - 5 minutes')" \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000001 

...
### UPDATE `sbtest`.`sbtest1`
### WHERE
###   @1=5 /* INT meta=0 nullable=0 is_null=0 */
###   @2=499813 /* INT meta=0 nullable=0 is_null=0 */
###   @3='44257470806-17967007152-32809666989-26174672567-29883439075-95767161284-94957565003-35708767253-53935174705-16168070783' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='34551750492-67990399350-81179284955-79299808058-21257255869' /* STRING(240) meta=65264 nullable=0 is_null=0 */
### SET
###   @1=5 /* INT meta=0 nullable=0 is_null=0 */
###   @2=0 /* INT meta=0 nullable=0 is_null=0 */
###   @3='44257470806-17967007152-32809666989-26174672567-29883439075-95767161284-94957565003-35708767253-53935174705-16168070783' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='34551750492-67990399350-81179284955-79299808058-21257255869' /* STRING(240) meta=65264 nullable=0 is_null=0 */
# Number of rows: 1
...

С флага --flashback изображението "преди" се разменя с изображението "след" на съществуващия ред:

$ mysqlbinlog -vv \
--start-datetime="$(date '+%F %T' -d 'now - 5 minutes')" \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000001 \
 --flashback

...
### UPDATE `sbtest`.`sbtest1`
### WHERE
###   @1=5 /* INT meta=0 nullable=0 is_null=0 */
###   @2=0 /* INT meta=0 nullable=0 is_null=0 */
###   @3='44257470806-17967007152-32809666989-26174672567-29883439075-95767161284-94957565003-35708767253-53935174705-16168070783' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='34551750492-67990399350-81179284955-79299808058-21257255869' /* STRING(240) meta=65264 nullable=0 is_null=0 */
### SET
###   @1=5 /* INT meta=0 nullable=0 is_null=0 */
###   @2=499813 /* INT meta=0 nullable=0 is_null=0 */
###   @3='44257470806-17967007152-32809666989-26174672567-29883439075-95767161284-94957565003-35708767253-53935174705-16168070783' /* STRING(480) meta=61152 nullable=0 is_null=0 */
###   @4='34551750492-67990399350-81179284955-79299808058-21257255869' /* STRING(240) meta=65264 nullable=0 is_null=0 */
...

След това можем да пренасочим изхода за ретроспекция към MySQL клиента, като по този начин върнем базата данни или таблицата до желания момент. Още примери са показани в следващите раздели.

MariaDB има специална страница с база знания за тази функция. Вижте страницата на базата знания на MariaDB Flashback.

MariaDB Flashback с MySQL

За да имате възможност за ретроспекция за MySQL, трябва да направите следното:

  • Копирайте помощната програма mysqlbinlog от всеки MariaDB сървър (10.2.4 или по-нова версия).
  • Деактивирайте MySQL GTID, преди да приложите SQL файла за ретроспекция. Глобалните променливи gtid_mode и enforce_gtid_consistency могат да се задават по време на изпълнение от MySQL 5.7.5.

Да предположим, че имаме следната проста топология за репликация на MySQL 8.0:

В този пример копирахме помощната програма mysqlbinlog от най-новата MariaDB 10.4 на един от нашите MySQL 8.0 slave (slave2):

(mariadb-server)$ scp /bin/mysqlbinlog [email protected]:/root/
(slave2-mysql8)$ ls -l /root/mysqlbinlog
-rwxr-xr-x. 1 root root 4259504 Feb 27 13:44 /root/mysqlbinlog

Помощната програма mysqlbinlog на нашата MariaDB вече се намира в /root/mysqlbinlog на slave2. В MySQL master изпълнихме следното катастрофално изявление:

mysql> DELETE FROM sbtest1 WHERE id BETWEEN 5 AND 100;
Query OK, 96 rows affected (0.01 sec)

96 реда бяха изтрити в горното изявление. Изчакайте няколко секунди, за да позволите на събитията да се репликират от главен към всички подчинени, преди да можем да се опитаме да намерим binlog позицията на катастрофалното събитие на подчинения сървър. Първата стъпка е да извлечете всички двоични регистрационни файлове на този сървър:

mysql> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name      | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000001 |       850 |        No |
| binlog.000002 |     18796 |        No |
+---------------+-----------+-----------+

Нашето катастрофално събитие трябва да съществува в binlog.000002, най-новия двоичен регистрационен файл на този сървър. След това можем да използваме помощната програма mysqlbinlog на MariaDB, за да извлечем всички binlog събития за таблица sbtest1 от преди 10 минути:

(slave2-mysql8)$ /root/mysqlbinlog -vv \
--start-datetime="$(date '+%F %T' -d 'now - 10 minutes')" \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000002

...
# at 195
#200228 15:09:45 server id 37001  end_log_pos 281 CRC32 0x99547474 Ignorable
# Ignorable event type 33 (MySQL Gtid)
# at 281
#200228 15:09:45 server id 37001  end_log_pos 353 CRC32 0x8b12bd3c Query thread_id=19 exec_time=0 error_code=0
SET TIMESTAMP=1582902585/*!*/;
SET @@session.pseudo_thread_id=19/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=524288/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;

BEGIN
/*!*/;
# at 353
#200228 15:09:45 server id 37001  end_log_pos 420 CRC32 0xe0e44a1b Table_map: `sbtest`.`sbtest1` mapped to number 92

# at 420
# at 8625
# at 16830
#200228 15:09:45 server id 37001  end_log_pos 8625 CRC32 0x99b1a8fc Delete_rows: table id 92
#200228 15:09:45 server id 37001  end_log_pos 16830 CRC32 0x89496a07 Delete_rows: table id 92
#200228 15:09:45 server id 37001  end_log_pos 18765 CRC32 0x302413b2 Delete_rows: table id 92 flags: STMT_END_F

За да намерите лесно номера на позицията на binlog, обърнете внимание на редовете, които започват с "# в ". От горните редове можем да видим, че събитието DELETE се случва на позиция 281 в binlog.000002 (започва от "# в 281"). Можем също да извлечем събитията binlog директно в MySQL сървър:

mysql> SHOW BINLOG EVENTS IN 'binlog.000002';
+---------------+-------+----------------+-----------+-------------+-------------------------------------------------------------------+
| Log_name      | Pos   | Event_type     | Server_id | End_log_pos | Info                                                              |
+---------------+-------+----------------+-----------+-------------+-------------------------------------------------------------------+
| binlog.000002 |     4 | Format_desc    |     37003 | 124         | Server ver: 8.0.19, Binlog ver: 4                                 |
| binlog.000002 |   124 | Previous_gtids |     37003 | 195         | 0d98d975-59f8-11ea-bd30-525400261060:1                            |
| binlog.000002 |   195 | Gtid           |     37001 | 281         | SET @@SESSION.GTID_NEXT= '0d98d975-59f8-11ea-bd30-525400261060:2' |
| binlog.000002 |   281 | Query          |     37001 | 353         | BEGIN                                                             |
| binlog.000002 |   353 | Table_map      |     37001 | 420         | table_id: 92 (sbtest.sbtest1)                                     |
| binlog.000002 |   420 | Delete_rows    |     37001 | 8625        | table_id: 92                                                      |
| binlog.000002 |  8625 | Delete_rows    |     37001 | 16830       | table_id: 92                                                      |
| binlog.000002 | 16830 | Delete_rows    |     37001 | 18765       | table_id: 92 flags: STMT_END_F                                    |
| binlog.000002 | 18765 | Xid            |     37001 | 18796       | COMMIT /* xid=171006 */                                           |
+---------------+-------+----------------+-----------+-------------+-------------------------------------------------------------------+

9 rows in set (0.00 sec)

Сега можем да потвърдим, че позиция 281 е мястото, където искаме данните ни да се върнат. След това можем да използваме флага --start-position, за да генерираме точни ретроспекции. Забележете, че пропускаме флага "-vv" и добавете флага --flashback:

(slave2-mysql8)$ /root/mysqlbinlog \
--start-position=281 \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000002 \
--flashback > /root/flashback.binlog

Flashback.binlog съдържа всички необходими събития за отмяна на всички промени, настъпили в таблица sbtest1 на този MySQL сървър. Тъй като това е подчинен възел на клъстер за репликация, трябва да прекъснем репликацията на избрания подчинен (slave2), за да го използваме за целите на репликация. За да направим това, трябва да спрем репликацията на избрания подчинен, да зададем MySQL GTID на ON_PERMISSIVE и да направим подчинения достъпен за запис:

mysql> STOP SLAVE; 
SET GLOBAL gtid_mode = ON_PERMISSIVE; 
SET GLOBAL enforce_gtid_consistency = OFF; 
SET GLOBAL read_only = OFF;

В този момент slave2 не е част от репликацията и нашата топология изглежда така:

Импортирайте ретроспекцията чрез mysql клиент и не искаме тази промяна да бъде записани в MySQL двоичен дневник:

(slave2-mysql8)$ mysql -uroot -p --init-command='SET sql_log_bin=0' sbtest < /root/flashback.binlog

След това можем да видим всички изтрити редове, както е доказано от следното изявление:

mysql> SELECT COUNT(id) FROM sbtest1 WHERE id BETWEEN 5 and 100;
+-----------+
| COUNT(id) |
+-----------+
|        96 |
+-----------+
1 row in set (0.00 sec)

След това можем да създадем SQL дъмп файл за таблица sbtest1 за наша справка:

(slave2-mysql8)$ mysqldump -uroot -p --single-transaction sbtest sbtest1 > sbtest1_flashbacked.sql

След като операцията за репликация приключи, можем да се присъединим отново към подчинения възел обратно във веригата за репликация. Но първо, трябва да върнем базата данни в последователно състояние, като възпроизведем всички събития, започвайки от позицията, която сме записали. Не забравяйте да пропуснете двоичното регистриране, тъй като не искаме да "записваме" на подчинения и да рискуваме себе си с грешни транзакции:

(slave2-mysql8)$ /root/mysqlbinlog \
--start-position=281 \
--database=sbtest \
--table=sbtest1 \
/var/lib/mysql/binlog.000002 | mysql -uroot -p --init-command='SET sql_log_bin=0' sbtest

Накрая подгответе възела обратно към ролята му на подчинен MySQL и стартирайте репликацията:

mysql> SET GLOBAL read_only = ON;
SET GLOBAL enforce_gtid_consistency = ON; 
SET GLOBAL gtid_mode = ON; 
START SLAVE; 

Проверете дали подчинения възел се репликира правилно:

mysql> SHOW SLAVE STATUS\G
...
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
...

В този момент ние отново присъединихме подчинения към веригата за репликация и нашата топология вече се връща в първоначалното си състояние:

Поздравете екипа на MariaDB за представянето на тази поразителна функция!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Напишете оптимизации за Qualcomm Centriq 2400 в MariaDB 10.3.5 Release Candidate

  2. Как RADIANS() работи в MariaDB

  3. Как DATE_SUB() работи в MariaDB

  4. Как да извадите минути от стойност на дата и час в MariaDB

  5. Как да разположите базата данни на Chamilo MariaDB за висока достъпност