sql >> Database teknologi >  >> RDS >> MariaDB

Håndtering af replikeringsproblemer fra ikke-GTID til GTID MariaDB-databaseklynger

Vi stødte for nylig ind i en interessant kundesupportsag, der involverede en MariaDB-replikeringsopsætning. Vi brugte meget tid på at undersøge dette problem og tænkte, at det ville være værd at dele dette med dig i dette blogindlæg.

Kundens miljøbeskrivelse

Problemet var som følger:en gammel (før 10.x) MariaDB-server var i brug, og der blev gjort et forsøg på at migrere data fra den til nyere MariaDB-replikeringsopsætning. Dette resulterede i problemer med at bruge Mariabackup til at genopbygge slaver i den nye replikeringsklynge. Til formålet med testene genskabte vi denne adfærd i følgende miljø:

Dataene er blevet migreret fra 5.5 til 10.4 ved hjælp af mysqldump:

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

Dette gjorde det muligt for os at indsamle master binære log-koordinater og det konsistente dump. Som et resultat var vi i stand til at klargøre MariaDB 10.4-masterknude og konfigurere replikeringen mellem gammel 5.5-master og ny 10.4-knude. Trafikken kørte stadig på 5.5 node. 10.4 master genererede GTID'er, da den skulle replikere data til 10.4 slave. Før vi graver i detaljer, lad os tage et hurtigt kig på, hvordan GTID'er fungerer i MariaDB.

MariaDB og GTID

Til at begynde med bruger MariaDB et andet format af GTID end Oracle MySQL. Den består af tre tal adskilt af bindestreger:

0 - 1 - 345

Først er et replikeringsdomæne, som gør det muligt at håndtere flerkildereplikering korrekt. Dette er ikke relevant for vores tilfælde, da alle noderne er i det samme replikationsdomæne. Andet nummer er server-id'et for den node, der genererede GTID'et. Den tredje er sekvensnummeret - det stiger monotont for hver hændelse, der er gemt i de binære logfiler.

MariaDB bruger flere variabler til at gemme informationen om GTID'er udført på en given node. De mest interessante for os er:

Gtid_binlog_pos - ifølge dokumentationen er denne variabel GTID'et for den sidste hændelsesgruppe skrevet til den binære log.

Gtid_slave_pos - i henhold til dokumentationen indeholder denne systemvariabel GTID'et for den sidste transaktion, der blev anvendt til databasen af ​​serverens slavetråde.

Gtid_current_pos - i henhold til dokumentationen indeholder denne systemvariabel GTID'et for den sidste transaktion anvendt på databasen. Hvis server_id'et for det tilsvarende GTID i gtid_binlog_pos er lig med serverens eget server_id, og sekvensnummeret er højere end det tilsvarende GTID i gtid_slave_pos, vil GTID'et fra gtid_binlog_pos blive brugt. Ellers vil GTID'et fra gtid_slave_pos blive brugt til det pågældende domæne.

Så, for at gøre det klart, gemmer gtid_binlog_pos GTID for den sidste lokalt udførte begivenhed. Gtid_slave_pos gemmer GTID af hændelsen udført af slavetråden, og gtid_current_pos viser enten værdien fra gtid_binlog_pos, hvis den har det højeste sekvensnummer, og den har server-id eller gtid_slave_pos, hvis den har den højeste sekvens. Husk dette.

En oversigt over problemet

Starttilstanden for de relevante variable er på 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)

Bemærk venligst gtid_slave_pos, som teoretisk set ikke giver mening - det kom fra den samme node, men via slavetråd. Dette kan ske, hvis du laver et hovedskifte før. Vi gjorde netop det - med to 10.4 noder skiftede vi masterne fra vært med server-id på 1001 til vært med server-id på 1002 og derefter tilbage til 1001.

Bagefter konfigurerede vi replikeringen fra 5.5 til 10.4, og sådan så tingene ud:

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)

Som du kan se, er hændelserne replikeret fra MariaDB 5.5 alle blevet taget højde for i gtid_binlog_pos-variablen:alle hændelser med server-ID på 55. Dette resulterer i et alvorligt problem. Som du måske husker, bør gtid_binlog_pos indeholde hændelser, der udføres lokalt på værten. Her indeholder den hændelser replikeret fra en anden server med et andet server-id.

Dette gør tingene vanskelige, når du vil genopbygge 10.4-slaven, her er hvorfor. Mariabackup fungerer ligesom Xtrabackup på en enkel måde. Den kopierer filerne fra MariaDB-serveren, mens den scanner gentag-logfiler og gemmer alle indgående transaktioner. Når filerne er blevet kopieret, vil Mariabackup fryse databasen ved at bruge enten FLUSH TABELS MED LÆSELÅS eller backuplåse, afhængigt af MariaDB-versionen og tilgængeligheden af ​​sikkerhedskopieringslåsene. Derefter læser den det senest udførte GTID og gemmer det sammen med sikkerhedskopien. Derefter frigøres låsen, og backup er fuldført. Det GTID, der er gemt i sikkerhedskopien, skal bruges som det senest udførte GTID på en node. I tilfælde af genopbygning af slaver vil den blive sat som en gtid_slave_pos og derefter brugt til at starte GTID-replikeringen. Dette GTID er taget fra gtid_current_pos, hvilket giver perfekt mening - det er trods alt "GTID'et for den sidste transaktion, der blev anvendt på databasen". Akut læser kan allerede se problemet. Lad os vise outputtet af variablerne, når 10.4 replikerer fra 5.5-masteren:

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 er indstillet til 0-1001-1. Dette er bestemt ikke det rigtige tidspunkt, det er taget fra gtid_slave_pos, mens vi har en masse transaktioner, der kom fra 5.5 efter det. Problemet er, at disse transaktioner er gemt som gtid_binlog_pos. På den anden side beregnes gtid_current_pos på en måde, at det kræver lokal server-id for GTID'er i gitd_binlog_pos, før de kan bruges som gtid_current_pos. I vores tilfælde har de server-id'et for 5.5-noden, så de vil ikke blive behandlet korrekt som hændelser udført på 10.4-masteren. Efter backupgendannelse, hvis du ville indstille slaven i henhold til GTID-tilstanden, der er gemt i sikkerhedskopien, ville den ende med at genanvende alle hændelser, der kom fra 5.5. Dette ville naturligvis bryde replikationen.

Løsningen

En løsning på dette problem er at tage flere yderligere trin:

  1. Stop replikeringen fra 5.5 til 10.4. Kør STOP SLAVE på 10.4 master
  2. Udfør enhver transaktion den 10.4 - OPRET SKEMA, HVIS IKKE FINDER fejlrettelse - dette vil ændre GTID-situationen som denne:
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)

Den seneste GITD blev udført lokalt, så den blev gemt som gtid_binlog_pos. Da det har det lokale server-id, er det valgt som gtid_current_pos. Nu kan du tage en sikkerhedskopi og bruge den til at genopbygge slaver fra 10.4 master. Når dette er gjort, skal du starte slavetråden igen.

MariaDB er klar over, at denne type fejl findes, en af ​​de relevante fejlrapporter, vi fandt er: https://jira.mariadb.org/browse/MDEV-10279 Desværre er der ingen rettelse indtil videre . Det, vi fandt, er, at dette problem påvirker MariaDB op til 5.5. Ikke-GTID-hændelser, der kommer fra MariaDB 10.0, regnes korrekt den 10.4 som kommer fra slavetråden, og gtid_slave_pos er korrekt opdateret. MariaDB 5.5 er ret gammel (selvom den stadig understøttes), så du kan stadig se opsætninger køre på den og forsøge at migrere fra 5.5 til nyere, GTID-aktiverede MariaDB-versioner. Hvad værre er, ifølge den fejlrapport, vi fandt, påvirker dette også replikering, der kommer fra ikke-MariaDB-servere (en af ​​kommentarerne nævner et problem, der dukker op på Percona Server 5.6) servere til MariaDB.

I hvert fald håber vi, at du fandt dette blogindlæg nyttigt, og forhåbentlig vil du ikke løbe ind i det problem, vi lige har beskrevet.


  1. Kontroller/ændre kompatibilitetsniveauet for en database i SQL Server (SSMS)

  2. ASCII()-funktion i Oracle

  3. Hvordan ændres tabelstrukturen i Oracle?

  4. Sådan skriver du lagrede procedurer til professionelle SSRS-rapporter