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

Обработване на проблеми с репликацията от не-GTID към GTID MariaDB клъстери от база данни

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

Описание на средата на клиента

Проблемът беше следният:използваше се стар (преди 10.x) сървър на MariaDB и беше направен опит за мигриране на данни от него в по-нова настройка за репликация на MariaDB. Това доведе до проблеми с използването на Mariabackup за възстановяване на подчинени устройства в новия клъстер за репликация. За целите на тестовете пресъздадохме това поведение в следната среда:

Данните са мигрирани от 5.5 на 10.4 с помощта на mysqldump:

mysqldump --single-transaction --master-data=2 --events --routines sbtest > /root/dump.sql

Това ни позволи да съберем главните двоични координати на регистрационния файл и последователното дъмп. В резултат на това успяхме да предоставим MariaDB 10.4 главен възел и да настроим репликацията между стария 5.5 главен и нов 10.4 възел. Трафикът все още работеше на 5.5 възел. 10.4 master генерираше GTID, тъй като трябваше да репликира данни на 10.4 slave. Преди да се задълбочим в подробности, нека да разгледаме набързо как работи GTID в MariaDB.

MariaDB и GTID

За начало MariaDB използва различен формат на GTID от Oracle MySQL. Състои се от три числа, разделени с тирета:

0 - 1 - 345

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

MariaDB използва няколко променливи, за да съхранява информацията за GTID, изпълнявани на даден възел. Най-интересните за нас са:

Gtid_binlog_pos - според документацията тази променлива е GTID на последната група събития, записана в двоичния дневник.

Gtid_slave_pos - съгласно документацията, тази системна променлива съдържа GTID на последната транзакция, приложена към базата данни от подчинените нишки на сървъра.

Gtid_current_pos - съгласно документацията, тази системна променлива съдържа GTID на последната транзакция, приложена към базата данни. Ако server_id на съответния GTID в gtid_binlog_pos е равен на собствения server_id на сървъра и поредният номер е по-висок от съответния GTID в gtid_slave_pos, тогава ще се използва GTID от gtid_binlog_pos. В противен случай GTID от gtid_slave_pos ще се използва за този домейн.

И така, за да стане ясно, gtid_binlog_pos съхранява GTID на последното локално изпълнено събитие. Gtid_slave_pos съхранява GTID на събитието, изпълнено от подчинената нишка, а gtid_current_pos показва или стойността от gtid_binlog_pos, ако има най-висок пореден номер и има server-id или gtid_slave_pos, ако има най-високата последователност. Моля, запомнете това.

Преглед на проблема

Първоначалното състояние на съответните променливи е на 10.4 master:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+----------+

| Variable_name           | Value |

+-------------------------+----------+

| gtid_binlog_pos         | 0-1001-1 |

| gtid_binlog_state       | 0-1001-1 |

| gtid_cleanup_batch_size | 64       |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+----------+

11 rows in set (0.001 sec)

Моля, обърнете внимание на gtid_slave_pos, което теоретично няма смисъл – идва от същия възел, но чрез подчинена нишка. Това може да се случи, ако преди това направите главен превключвател. Направихме точно това – с два 10.4 възела превключихме главните от хост с идентификатор на сървъра 1001 на хост с идентификатор на сървъра 1002 и след това обратно към 1001.

След това конфигурирахме репликацията от 5.5 до 10.4 и така изглеждаха нещата:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Както можете да видите, събитията, репликирани от MariaDB 5.5, всички те са отчетени в променливата gtid_binlog_pos:всички събития с идентификатор на сървъра 55. Това води до сериозен проблем. Както може би си спомняте, gtid_binlog_pos трябва да съдържа събития, изпълнявани локално на хоста. Тук той съдържа събития, репликирани от друг сървър с различен идентификатор на сървъра.

Това прави нещата сложни, когато искате да възстановите подчинения 10.4, ето защо. Mariabackup, точно като Xtrabackup, работи по прост начин. Той копира файловете от сървъра на MariaDB, докато сканира регистрационните файлове за повторно изпълнение и съхранява всички входящи транзакции. Когато файловете бъдат копирани, Mariabackup ще замрази базата данни, като използва или FLUSH TABLES WITH READ LOCK, или архивиране, в зависимост от версията на MariaDB и наличността на заключванията за архивиране. След това чете последния изпълнен GTID и го съхранява заедно с архива. След това заключването се освобождава и архивирането е завършено. GTID, съхранен в архива, трябва да се използва като последния изпълнен GTID на възел. В случай на повторно изграждане на подчинени устройства, той ще бъде поставен като gtid_slave_pos и след това ще се използва за стартиране на репликацията на GTID. Този GTID е взет от gtid_current_pos, което е напълно логично - в края на краищата това е „GTID на последната транзакция, приложена към базата данни“. Остър читател вече може да види проблема. Нека покажем изхода на променливите, когато 10.4 се репликира от главния 5.5:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Gtid_current_pos е настроен на 0-1001-1. Това определено не е правилният момент във времето, взето е от gtid_slave_pos, докато имаме куп транзакции, които идват от 5.5 след това. Проблемът е, че тези транзакции се съхраняват като gtid_binlog_pos. От друга страна gtid_current_pos се изчислява по начин, че изисква идентификатор на локален сървър за GTID в gitd_binlog_pos, преди да могат да бъдат използвани като gtid_current_pos. В нашия случай те имат идентификатора на сървъра на възела 5.5, така че няма да бъдат третирани правилно като събития, изпълнявани на 10.4 master. След възстановяване на архива, ако зададете подчинения според състоянието на GTID, съхранено в архива, в крайна сметка ще приложи повторно всички събития, дошли от 5.5. Това, очевидно, би нарушило репликацията.

Решението

Решение на този проблем е да предприемете няколко допълнителни стъпки:

  1. Спрете репликацията от 5.5 до 10.4. Стартирайте STOP SLAVE на 10.4 master
  2. Изпълнете всяка транзакция на 10.4 - СЪЗДАВАЙТЕ СХЕМА, АКО НЕ СЪЩЕСТВУВА, корекция на грешка - това ще промени ситуацията с GTID по следния начин:
MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+---------------------------+

| Variable_name           | Value   |

+-------------------------+---------------------------+

| gtid_binlog_pos         | 0-1001-117122   |

| gtid_binlog_state       | 0-55-117121,0-1001-117122 |

| gtid_cleanup_batch_size | 64                        |

| gtid_current_pos        | 0-1001-117122   |

| gtid_domain_id          | 0   |

| gtid_ignore_duplicates  | ON   |

| gtid_pos_auto_engines   |   |

| gtid_slave_pos          | 0-1001-1   |

| gtid_strict_mode        | ON   |

| wsrep_gtid_domain_id    | 0   |

| wsrep_gtid_mode         | OFF   |

+-------------------------+---------------------------+

11 rows in set (0.001 sec)

Последният GITD беше изпълнен локално, така че беше съхранен като gtid_binlog_pos. Тъй като има идентификатор на локалния сървър, той е избран като gtid_current_pos. Сега можете да направите резервно копие и да го използвате за възстановяване на подчинени устройства от 10.4 master. След като това стане, стартирайте отново подчинената нишка.

MariaDB е наясно, че този вид грешка съществува, един от съответните доклади за грешки, които открихме е: https://jira.mariadb.org/browse/MDEV-10279 За съжаление, досега няма поправка . Това, което открихме, е, че този проблем засяга MariaDB до 5.5. Не-GTID събития, които идват от MariaDB 10.0, се отчитат правилно на 10.4 като идващи от подчинената нишка и gtid_slave_pos е правилно актуализиран. MariaDB 5.5 е доста стара (въпреки че все още се поддържа), така че все още може да видите настройки, работещи на него, и опити за мигриране от 5.5 към по-нови версии на MariaDB с активиран GTID. По-лошото е, че според доклада за грешки, който открихме, това също засяга репликацията, идваща от сървъри, които не са MariaDB (един от коментарите споменава проблем, който се появява на Percona Server 5.6) в 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. Какво заслужават нашите клиенти:Представяне на MariaDB Enterprise Documentation

  2. Планиране за аварийно възстановяване за MySQL и MariaDB

  3. Разширено отказване с помощта на кукички за пост/предварителен скрипт

  4. Ресурси за архивиране на база данни на MySQL и MariaDB

  5. Разбиране на детайлността на заключване в MySQL