sql >> Database >  >> RDS >> MariaDB

Replicatieproblemen van niet-GTID naar GTID verwerken MariaDB-databaseclusters

We kwamen onlangs een interessant klantondersteuningsgeval tegen met een MariaDB-replicatie-installatie. We hebben veel tijd besteed aan het onderzoeken van dit probleem en dachten dat het de moeite waard zou zijn om dit met u te delen in deze blogpost.

Omgeving klantomgeving

Het probleem was als volgt:er was een oude MariaDB-server (vóór 10.x) in gebruik en er is geprobeerd gegevens ervan te migreren naar een recentere MariaDB-replicatieconfiguratie. Dit resulteerde in problemen met het gebruik van Mariabackup om slaves opnieuw op te bouwen in het nieuwe replicatiecluster. Ten behoeve van de tests hebben we dit gedrag in de volgende omgeving nagebootst:

De gegevens zijn gemigreerd van 5.5 naar 10.4 met behulp van mysqldump:

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

Hierdoor konden we master-binaire log-coördinaten en de consistente dump verzamelen. Als resultaat waren we in staat om MariaDB 10.4 master node in te richten en de replicatie tussen oude 5.5 master en nieuwe 10.4 node op te zetten. Het verkeer liep nog steeds op 5.5 node. 10.4 master genereerde GTID's omdat het gegevens moest repliceren naar 10.4 slave. Laten we, voordat we ingaan op details, eens kijken hoe GTID's werken in MariaDB.

MariaDB en GTID

Om te beginnen gebruikt MariaDB een ander formaat van de GTID dan Oracle MySQL. Het bestaat uit drie getallen gescheiden door streepjes:

0 - 1 - 345

First is een replicatiedomein, waarmee multi-source replicatie correct kan worden afgehandeld. Dit is niet relevant voor ons geval, aangezien alle knooppunten zich in hetzelfde replicatiedomein bevinden. Het tweede nummer is de server-ID van het knooppunt dat de GTID heeft gegenereerd. De derde is het volgnummer - het neemt monotoon toe met elke gebeurtenis die wordt opgeslagen in de binaire logs.

MariaDB gebruikt verschillende variabelen om de informatie op te slaan over GTID's die op een bepaald knooppunt worden uitgevoerd. De meest interessante voor ons zijn:

Gtid_binlog_pos - volgens de documentatie is deze variabele de GTID van de laatste gebeurtenisgroep die naar het binaire logboek is geschreven.

Gtid_slave_pos - volgens de documentatie bevat deze systeemvariabele de GTID van de laatste transactie die door de slave-threads van de server op de database is toegepast.

Gtid_current_pos - volgens de documentatie bevat deze systeemvariabele de GTID van de laatste transactie die op de database is toegepast. Als de server_id van de corresponderende GTID in gtid_binlog_pos gelijk is aan de eigen server_id van de server, en het volgnummer is hoger dan de corresponderende GTID in gtid_slave_pos, dan zal de GTID van gtid_binlog_pos worden gebruikt. Anders wordt de GTID van gtid_slave_pos gebruikt voor dat domein.

Dus, om het duidelijk te maken, gtid_binlog_pos slaat GTID op van de laatste lokaal uitgevoerde gebeurtenis. Gtid_slave_pos slaat GTID op van de gebeurtenis die door de slavethread wordt uitgevoerd en gtid_current_pos toont ofwel de waarde van gtid_binlog_pos, als het het hoogste volgnummer heeft en het heeft server-id of gtid_slave_pos als het de hoogste volgorde heeft. Houd hier rekening mee.

Een overzicht van het probleem

De initiële status van de relevante variabelen is op 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)

Let op gtid_slave_pos, wat in theorie niet logisch is - het kwam van hetzelfde knooppunt maar via een slave-thread. Dit kan gebeuren als u eerder een hoofdschakelaar maakt. Dat hebben we gedaan - met twee 10.4 nodes schakelden we de masters over van host met server-ID van 1001 naar host met server-ID van 1002 en vervolgens terug naar 1001.

Daarna hebben we de replicatie geconfigureerd van 5.5 naar 10.4 en zo zag het er uit:

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)

Zoals je kunt zien, zijn de gebeurtenissen gerepliceerd vanuit MariaDB 5.5, ze zijn allemaal verantwoord in de variabele gtid_binlog_pos:alle gebeurtenissen met een server-ID van 55. Dit resulteert in een serieus probleem. Zoals je je misschien herinnert, zou gtid_binlog_pos gebeurtenissen moeten bevatten die lokaal op de host worden uitgevoerd. Hier bevat het gebeurtenissen die zijn gerepliceerd vanaf een andere server met een ander server-ID.

Dit maakt het lastig als je de 10.4-slave wilt herbouwen, dit is waarom. Mariabackup werkt, net als Xtrabackup, op een eenvoudige manier. Het kopieert de bestanden van de MariaDB-server terwijl het opnieuw logs scant en alle inkomende transacties opslaat. Wanneer de bestanden zijn gekopieerd, bevriest Mariabackup de database met behulp van FLUSH TABLES WITH READ LOCK of back-upvergrendelingen, afhankelijk van de MariaDB-versie en de beschikbaarheid van de back-upvergrendelingen. Vervolgens leest het de laatst uitgevoerde GTID en slaat het op naast de back-up. Vervolgens wordt de vergrendeling vrijgegeven en is de back-up voltooid. De GTID die in de back-up is opgeslagen, moet worden gebruikt als de laatst uitgevoerde GTID op een knooppunt. In het geval van het opnieuw opbouwen van slaves, wordt het als een gtid_slave_pos geplaatst en vervolgens gebruikt om de GTID-replicatie te starten. Deze GTID is afkomstig van gtid_current_pos, wat volkomen logisch is - het is tenslotte de "GTID van de laatste transactie die op de database is toegepast". De acute lezer ziet het probleem al. Laten we de uitvoer van de variabelen laten zien wanneer 10.4 repliceert van de 5.5-master:

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 is ingesteld op 0-1001-1. Dit is absoluut niet het juiste moment in de tijd, het is overgenomen van gtid_slave_pos terwijl we een heleboel transacties hebben die daarna van 5.5 kwamen. Het probleem is dat die transacties worden opgeslagen als gtid_binlog_pos. Aan de andere kant wordt gtid_current_pos zo berekend dat het een lokale server-ID vereist voor GTID's in gitd_binlog_pos voordat ze kunnen worden gebruikt als de gtid_current_pos. In ons geval hebben ze de server-ID van het 5.5-knooppunt, zodat ze niet correct worden behandeld als gebeurtenissen die worden uitgevoerd op de 10.4-master. Als u na het herstellen van de back-up de slave zou instellen volgens de GTID-status die in de back-up is opgeslagen, zou het uiteindelijk alle gebeurtenissen die uit 5.5 kwamen opnieuw toepassen. Dit zou uiteraard de replicatie verbreken.

De oplossing

Een oplossing voor dit probleem is het nemen van een aantal extra stappen:

  1. Stop de replicatie van 5.5 naar 10.4. Voer STOP SLAVE uit op 10.4 master
  2. Voer een transactie uit op 10.4 - MAAK SCHEMA ALS NIET BESTAAT bugfix - dit zal de GTID-situatie als volgt veranderen:
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)

De nieuwste GITD is lokaal uitgevoerd, dus het is opgeslagen als gtid_binlog_pos. Omdat het de lokale server-ID heeft, wordt het gekozen als de gtid_current_pos. Nu kunt u een back-up maken en deze gebruiken om slaves van 10.4 master opnieuw op te bouwen. Zodra dit is gebeurd, start u de slave-thread opnieuw.

MariaDB is zich ervan bewust dat dit soort bug bestaat, een van de relevante bugrapporten die we hebben gevonden is:https://jira.mariadb.org/browse/MDEV-10279 Helaas is er tot nu toe geen oplossing . Wat we hebben gevonden, is dat dit probleem van invloed is op MariaDB tot 5.5. Niet-GTID-gebeurtenissen die afkomstig zijn van MariaDB 10.0 worden correct geteld in 10.4 als afkomstig van de slave-thread en gtid_slave_pos is correct bijgewerkt. MariaDB 5.5 is vrij oud (hoewel het nog steeds wordt ondersteund), dus je kunt nog steeds instellingen zien draaien en pogingen om te migreren van 5.5 naar recentere, GTID-compatibele MariaDB-versies. Wat erger is, volgens het bugrapport dat we hebben gevonden, heeft dit ook invloed op replicatie afkomstig van niet-MariaDB (een van de opmerkingen vermeldt een probleem dat verschijnt op Percona Server 5.6)-servers naar MariaDB.

Hoe dan ook, we hopen dat je deze blogpost nuttig vond en hopelijk zul je niet het probleem tegenkomen dat we zojuist hebben beschreven.


  1. Transacties uitvoeren tijdens het uitvoeren van een postgreql-functie

  2. FieldShield SDK

  3. Samenvoegen tussen tabellen in twee verschillende databases?

  4. Fix "ERROR:ontbrekende FROM-clausule voor tabel" in PostgreSQL bij gebruik van UNION, BEHALVE of INTERSECT