sql >> Databáze >  >> RDS >> MariaDB

Řešení problémů s replikací z databázových klastrů bez GTID do GTID MariaDB

Nedávno jsme narazili na zajímavý případ zákaznické podpory týkající se nastavení replikace MariaDB. Strávili jsme spoustu času zkoumáním tohoto problému a mysleli jsme si, že by stálo za to se o to s vámi podělit v tomto příspěvku na blogu.

Popis prostředí zákazníka

Problém byl následující:používal se starý server MariaDB (před 10.x) a byl učiněn pokus o migraci dat z něj do novějšího nastavení replikace MariaDB. To vedlo k problémům s používáním Mariabackup k přestavbě slave v novém replikačním clusteru. Pro účely testů jsme toto chování znovu vytvořili v následujícím prostředí:

Data byla migrována z 5.5 na 10.4 pomocí mysqldump:

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

To nám umožnilo shromáždit souřadnice hlavního binárního protokolu a konzistentní výpis. Výsledkem bylo, že jsme byli schopni zřídit hlavní uzel MariaDB 10.4 a nastavit replikaci mezi starým hlavním uzlem 5.5 a novým uzlem 10.4. Provoz stále běžel na uzlu 5,5. 10.4 master generoval GTID, protože musel replikovat data na 10.4 slave. Než se pustíme do podrobností, pojďme se rychle podívat na to, jak GTID funguje v MariaDB.

MariaDB a GTID

Pro začátek, MariaDB používá jiný formát GTID než Oracle MySQL. Skládá se ze tří čísel oddělených pomlčkami:

0 – 1 – 345

První je replikační doména, která umožňuje správné zpracování replikace z více zdrojů. To není pro náš případ relevantní, protože všechny uzly jsou ve stejné replikační doméně. Druhé číslo je ID serveru uzlu, který vygeneroval GTID. Třetím je pořadové číslo – to se monotónně zvyšuje s každou událostí uloženou v binárních protokolech.

MariaDB používá několik proměnných k ukládání informací o GTID spuštěných na daném uzlu. Nejzajímavější pro nás jsou:

Gtid_binlog_pos – podle dokumentace je tato proměnná GTID poslední skupiny událostí zapsané do binárního protokolu.

Gtid_slave_pos – podle dokumentace tato systémová proměnná obsahuje GTID poslední transakce použité v databázi podřízenými vlákny serveru.

Gtid_current_pos - podle dokumentace tato systémová proměnná obsahuje GTID poslední transakce použité v databázi. Pokud se server_id odpovídajícího GTID v gtid_binlog_pos rovná vlastnímu serveru server_id a pořadové číslo je vyšší než odpovídající GTID v gtid_slave_pos, bude použito GTID z gtid_binlog_pos. Jinak bude pro danou doménu použito GTID z gtid_slave_pos.

Aby bylo jasno, gtid_binlog_pos ukládá GTID poslední lokálně provedené události. Gtid_slave_pos ukládá GTID události provedené podřízeným vláknem a gtid_current_pos ukazuje buď hodnotu z gtid_binlog_pos, pokud má nejvyšší pořadové číslo a má server-id, nebo gtid_slave_pos, pokud má nejvyšší sekvenci. Mějte to prosím na paměti.

Přehled problému

Počáteční stav příslušných proměnných je na masteru 10.4:

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)

Všimněte si prosím gtid_slave_pos, který teoreticky nedává smysl – pochází ze stejného uzlu, ale prostřednictvím podřízeného vlákna. To se může stát, pokud předtím provedete hlavní vypínač. Udělali jsme právě to - se dvěma 10.4 uzly jsme přepnuli master z hostitele s ID serveru 1001 na hostitele s ID serveru 1002 a pak zpět na 1001.

Poté jsme nakonfigurovali replikaci z 5.5 na 10.4 a takto to vypadalo:

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)

Jak můžete vidět, události replikované z MariaDB 5.5, všechny byly zaúčtovány v proměnné gtid_binlog_pos:všechny události s ID serveru 55. To má za následek vážný problém. Jak si možná pamatujete, gtid_binlog_pos by měl obsahovat události spouštěné lokálně na hostiteli. Zde obsahuje události replikované z jiného serveru s jiným ID serveru.

Když chcete přestavět 10.4 slave, tak to dělá věci složitými, zde je důvod. Mariabackup, stejně jako Xtrabackup, funguje jednoduchým způsobem. Kopíruje soubory ze serveru MariaDB, zatímco skenuje protokoly opakování a ukládá všechny příchozí transakce. Po zkopírování souborů Mariabackup zmrazí databázi pomocí buď VYPLACHOVÁNÍ TABULEK SE ZÁMEKEM ČTENÍ nebo zámků zálohy, v závislosti na verzi MariaDB a dostupnosti zálohovacích zámků. Poté přečte poslední provedené GTID a uloží je spolu se zálohou. Poté se zámek uvolní a zálohování je dokončeno. GTID uložené v záloze by mělo být použito jako poslední provedené GTID na uzlu. V případě přestavby slave bude umístěn jako gtid_slave_pos a poté použit ke spuštění replikace GTID. Toto GTID je převzato z gtid_current_pos, což dává dokonalý smysl – koneckonců je to „GTID poslední transakce použité v databázi“. Akutní čtenář už vidí problém. Pojďme si ukázat výstup proměnných, když se 10.4 replikuje z hlavního 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 je nastaveno na 0-1001-1. Toto rozhodně není správný okamžik, je to převzato z gtid_slave_pos, zatímco máme spoustu transakcí, které pocházely z 5.5 poté. Problém je v tom, že tyto transakce jsou uloženy jako gtid_binlog_pos. Na druhou stranu se gtid_current_pos vypočítává tak, že vyžaduje místní ID serveru pro GTID v gitd_binlog_pos, než je lze použít jako gtid_current_pos. V našem případě mají ID serveru uzlu 5.5, takže s nimi nebude správně zacházeno jako s událostmi spuštěnými na hlavním serveru 10.4. Pokud byste po obnovení zálohy nastavili slave podle stavu GTID uloženého v záloze, skončilo by to opětovným použitím všech událostí z 5.5. To by samozřejmě přerušilo replikaci.

Řešení

Řešením tohoto problému je provést několik dalších kroků:

  1. Zastavte replikaci z 5.5 na 10.4. Spusťte STOP SLAVE na 10.4 master
  2. Proveďte jakoukoli transakci v 10.4 – oprava chyby VYTVOŘIT SCHÉMA, POKUD NEEXISTUJE – změní situaci GTID takto:
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)

Nejnovější GITD byl spuštěn lokálně, takže byl uložen jako gtid_binlog_pos. Protože má ID místního serveru, je vybrán jako gtid_current_pos. Nyní si můžete udělat zálohu a použít ji k přestavbě otroků z 10.4 master. Jakmile to uděláte, spusťte znovu podřízené vlákno.

MariaDB si je vědoma, že tento druh chyby existuje, jedna z relevantních chybových zpráv, kterou jsme našli, je: https://jira.mariadb.org/browse/MDEV-10279 Bohužel zatím neexistuje žádná oprava . Zjistili jsme, že tento problém se týká MariaDB až do 5.5. Události bez GTID, které pocházejí z MariaDB 10.0, jsou správně zaúčtovány v 10.4 jako pocházející z podřízeného vlákna a gtid_slave_pos je správně aktualizováno. MariaDB 5.5 je docela stará (i když stále podporovaná), takže stále můžete vidět nastavení běžící na ní a pokusy o migraci z 5.5 na novější verze MariaDB s podporou GTID. A co je horší, podle zprávy o chybě, kterou jsme našli, to také ovlivňuje replikaci pocházející ze serverů jiných než MariaDB (jeden z komentářů zmiňuje problém, který se objevuje na serveru Percona Server 5.6) do MariaDB.

V každém případě doufáme, že pro vás byl tento příspěvek na blogu užitečný a doufáme, že nenarazíte na problém, který jsme právě popsali.


  1. Funkce LISTAGG() v Oracle

  2. SQL Server používá vysoký procesor při hledání uvnitř řetězců nvarchar

  3. SQLite LIKE

  4. Typy kurzoru serveru SQL Server – pouze vpřed dynamický kurzor | Kurz SQL Server / Kurz TSQL