Opsætning af replikering i MySQL er let, men det har aldrig været en nem opgave at administrere den i produktionen. Selv med den nyere GTID-autopositionering kan det stadig gå galt, hvis du ikke ved, hvad du laver. Efter opsætning af replikering kan alle mulige ting gå galt. Fejl kan nemt begås og kan få en katastrofal slutning for dine data.
Dette indlæg vil fremhæve nogle af de mest almindelige fejl, der er lavet med MySQL-replikering, og hvordan du kan forhindre dem.
Opsætning af replikering
Når du opsætter MySQL-replikering, skal du prime slaveknuderne med datasættet fra masteren. Med løsninger som Galera cluster håndteres dette automatisk for dig med den valgte metode. Til MySQL-replikering skal du gøre dette selv, så du tager naturligvis dit standard backupværktøj.
Til MySQL er der et stort udvalg af sikkerhedskopieringsværktøjer til rådighed, men det mest brugte er mysqldump. Mysqldump udsender en logisk sikkerhedskopi af din masters datasæt. Dette betyder, at kopien af dataene ikke bliver en binær kopi, men en stor fil, der indeholder forespørgsler til at genskabe dit datasæt. I de fleste tilfælde bør dette give dig en (næsten) identisk kopi af dine data, men der er tilfælde, hvor det ikke gør det - på grund af at dumpet er på et per objekt-basis. Det betyder, at selv før du begynder at replikere data, er dit datasæt ikke det samme som det på masteren.
Der er et par tweaks, du kan gøre for at gøre mysqldump mere pålidelig som dump som en enkelt transaktion, og glem heller ikke at inkludere rutiner og triggere:
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > dumpfile.sql
En god praksis er at kontrollere, om din slaveknude er 100 % den samme, er ved at bruge pt-table-checksum efter opsætning af replikeringen:
pt-table-checksum --replicate=test.checksums --ignore-databases mysql h=localhost,u=user,p=pass
Dette værktøj vil beregne en kontrolsum for hver tabel på masteren, replikere kommandoen til slaven, og derefter udfører slaveknuden den samme kontrolsum operation. Hvis nogen af tabellerne ikke er ens, bør dette være tydeligt synligt i kontrolsumtabellen.
Brug af den forkerte replikeringsmetode
Standardreplikeringsmetoden for MySQL var den såkaldte sætningsbaserede replikering. Denne metode er præcis, hvad den er:en replikeringsstrøm af hver sætning, der køres på masteren, og som vil blive afspillet på slaveknuden. Da MySQL i sig selv er multi-threaded, men dens (traditionelle) replikering ikke er, er rækkefølgen af udsagn i replikeringsstrømmen muligvis ikke 100 % den samme. Også genafspilning af en sætning kan give forskellige resultater, når den ikke udføres på nøjagtig samme tidspunkt.
Dette kan resultere i forskellige datasæt mellem master og slave på grund af datadrift. Dette var ikke et problem i mange år, da ikke mange kørte MySQL med mange samtidige tråde, men med moderne multi-CPU-arkitekturer er dette faktisk blevet højst sandsynligt på en normal daglig arbejdsbyrde.
Svaret fra MySQL var den såkaldte rækkebaserede replikering. Rækkebaseret replikering vil replikere dataene, når det er muligt, men i nogle ekstraordinære tilfælde bruges stadig sætninger. Et godt eksempel ville være DLL-ændringen af en tabel, hvor replikeringen så skulle kopiere hver række i tabellen gennem replikering. Da dette er ineffektivt, vil en sådan erklæring blive replikeret på den traditionelle måde. Når rækkebaseret replikering registrerer datadrift, stopper den slavetråden for at forhindre at tingene bliver værre.
Så er der en metode imellem disse to:mixed mode replikering. Denne type replikering vil altid replikere sætninger, undtagen når forespørgslen indeholder UUID()-funktionen, der bruges triggere, lagrede procedurer, UDF'er og nogle få andre undtagelser. Blandet tilstand vil ikke løse problemet med datadrift og bør sammen med sætningsbaseret replikering undgås.
Cirkulær replikering
At køre MySQL-replikering med multi-master er ofte nødvendigt, hvis du har et multi-datacenter-miljø. Da applikationen ikke kan vente på, at masteren i det andet datacenter anerkender din skrivning, foretrækkes en lokal master. Normalt bruges den automatiske stigningsforskydning til at forhindre datasammenstød mellem masterne. At lade to mestre udføre skrivninger til hinanden på denne måde er en bredt accepteret løsning.
MySQL Master-Master replikeringMen hvis du har brug for at skrive flere datacentre ind i den samme database, ender du med flere mastere, der skal skrive deres data til hinanden. Før MySQL 5.7.6 var der ingen metode til at lave en mesh-type replikering, så alternativet ville være at bruge en cirkulær ringreplikation i stedet for.
MySQL ringreplikeringstopologiRingreplikering i MySQL er problematisk af følgende årsager:latenstid, høj tilgængelighed og datadrift. Ved at skrive nogle data til server A, ville det tage tre hop at ende på server D (via server B og C). Da (traditionel) MySQL-replikering er enkelttrådet, kan enhver langvarig forespørgsel i replikeringen stoppe hele ringen. Også hvis nogen af serverne ville gå ned, ville ringen blive brudt, og i øjeblikket er der ingen failover-software, der kan reparere ringstrukturer. Så kan datadrift opstå, når data skrives til server A og ændres på samme tid på server C eller D.
Replikering af brudt ringGenerelt passer cirkulær replikering ikke godt sammen med MySQL, og det bør undgås for enhver pris. Galera ville være et godt alternativ til multi-datacenterskrivning, da den er designet med det i tankerne.
Standsering af din replikering med store opdateringer
Ofte vil forskellige husholdnings-batchjobs udføre forskellige opgaver, lige fra at rydde op i gamle data til beregning af gennemsnit af 'likes' hentet fra en anden kilde. Det betyder med faste intervaller, at et job vil skabe en masse databaseaktivitet og højst sandsynligt skrive en masse data tilbage til databasen. Dette betyder naturligvis, at aktiviteten i replikationsstrømmen vil stige lige meget.
Statement-baseret replikering vil replikere de nøjagtige forespørgsler, der er brugt i batch-jobbene, så hvis forespørgslen tog en halv time at behandle på masteren, vil slavetråden blive stoppet i mindst samme tid. Dette betyder, at ingen andre data kan replikere, og slaveknuderne vil begynde at halte bagefter masteren. Hvis dette overskrider tærsklen for dit failover-værktøj eller proxy, kan det fjerne disse slaveknuder fra de tilgængelige noder i klyngen. Hvis du bruger sætningsbaseret replikering, kan du forhindre dette ved at knuse dataene til dit job i mindre batches.
Nu tror du måske, at rækkebaseret replikering ikke er påvirket af dette, da det vil replikere rækkeoplysningerne i stedet for forespørgslen. Dette er delvist sandt, da for DDL-ændringer vender replikeringen tilbage til sætningsbaseret format. Også et stort antal CRUD-operationer vil påvirke replikeringsstrømmen:i de fleste tilfælde er dette stadig en enkelt trådoperation, og derfor vil hver transaktion vente på, at den forrige afspilles via replikering. Dette betyder, at hvis du har høj samtidighed på masteren, kan slaven gå i stå på grund af overbelastning af transaktioner under replikering.
For at omgå dette tilbyder både MariaDB og MySQL parallel replikering. Implementeringen kan variere fra leverandør og version. MySQL 5.6 tilbyder parallel replikering, så længe forespørgslerne er adskilt af skema. MariaDB 10.0 og MySQL 5.7 kan begge håndtere parallel replikering på tværs af skemaer, men har andre grænser. Udførelse af forespørgsler via parallelle slave-tråde kan fremskynde din replikeringsstrøm, hvis du skriver tungt. Men hvis du ikke er det, ville det være bedst at holde sig til den traditionelle enkelttrådede replikering.
Skemaændringer
At udføre skemaændringer på en kørende produktionsopsætning er altid en smerte. Dette hænger sammen med, at en DDL-ændring for det meste vil låse en tabel og først frigive denne lås, når DDL-ændringen er blevet anvendt. Det bliver endda værre, når du begynder at replikere disse DDL-ændringer gennem MySQL-replikering, hvor det desuden vil stoppe replikeringsstrømmen.
En ofte brugt løsning er først at anvende skemaændringen på slaveknuderne. For sætningsbaseret replikering fungerer dette fint, men for rækkebaseret replikering kan dette fungere op til en vis grad. Rækkebaseret replikering tillader ekstra kolonner at eksistere i slutningen af tabellen, så så længe det er i stand til at skrive de første kolonner, vil det være fint. Anvend først ændringen på alle slaver, derefter failover på en af slaverne og anvend derefter ændringen på masteren og tilknyt den som en slave. Hvis din ændring involverer indsættelse af en kolonne i midten eller fjernelse af en kolonne, vil dette fungere med rækkebaseret replikering.
Der er værktøjer rundt omkring, der kan udføre online skemaændringer mere pålideligt. Percona Online Schema Change (så kendt som pt-osc) vil skabe en skyggetabel med den nye tabelstruktur, indsætte nye data via triggere og udfylde data i baggrunden. Når den er færdig med at oprette den nye tabel, vil den simpelthen bytte den gamle ud med den nye tabel i en transaktion. Dette virker ikke i alle tilfælde, især hvis din eksisterende tabel allerede har triggere.
Et alternativ er det nye Gh-ost-værktøj fra Github. Dette online skemaændringsværktøj vil først lave en kopi af dit eksisterende tabellayout, ændre tabellen til det nye layout og derefter tilslutte processen som en MySQL-replika. Den vil gøre brug af replikeringsstrømmen til at finde nye rækker, der er blevet indsat i den originale tabel, og samtidig udfylder den tabellen. Når den er færdig med at udfylde, skifter den originale og den nye tabel. Naturligvis vil alle operationer til den nye tabel også ende i replikeringsstrømmen, således på hver replika sker migreringen på samme tid.
Hukommelsestabeller og replikering
Mens vi er om emnet DDL'er, er et almindeligt problem oprettelsen af hukommelsestabeller. Hukommelsestabeller er ikke-vedvarende tabeller, deres tabelstruktur forbliver, men de mister deres data efter en genstart af MySQL. Når du opretter en ny hukommelsestabel på både en master og en slave, vil begge have en tom tabel, og dette vil fungere helt fint. Når en af dem er genstartet, vil tabellen blive tømt, og der vil opstå replikeringsfejl.
Rækkebaseret replikering vil bryde, når dataene i slaveknuden returnerer forskellige resultater, og sætningsbaseret replikering vil bryde, når den forsøger at indsætte data, der allerede eksisterer. For hukommelsestabeller er dette en hyppig replikeringsafbryder. Rettelsen er nem:Lav blot en ny kopi af dataene, skift motoren til InnoDB, og den skulle nu være replikeringssikker.
Indstilling af read_only-variablen til True
Som vi beskrev tidligere, kan replikering brydes, hvis du ikke har de samme data i slaveknuderne. Ofte er dette forårsaget af, at noget (eller nogen) har ændret dataene på slaveknuden, men ikke på masternoden. Når masternodens data bliver ændret, vil disse blive replikeret til slaven, hvor den ikke kan anvende ændringen, og dette får replikationen til at bryde.
Der er en nem forebyggelse for dette:at indstille read_only-variablen til sand. Dette vil ikke tillade nogen at foretage ændringer i dataene, undtagen for replikering og root-brugere. De fleste failover-administratorer indstiller dette flag automatisk for at forhindre brugere i at skrive til den brugte master under failover. Nogle af dem beholder endda dette efter failover.
Dette overlader stadig root-brugeren til at udføre en fejlagtig CRUD-forespørgsel på slaveknuden. For at forhindre dette i at ske, er der en super_read_only-variabel siden MySQL 5.7.8, der endda låser root-brugeren ude fra at opdatere data.
Aktivere GTID
I MySQL-replikering er det vigtigt at starte slaven fra den korrekte position i de binære logfiler. At opnå denne position kan gøres, når du laver en sikkerhedskopi (xtrabackup og mysqldump understøtter dette), eller når du er stoppet med at slave på en node, som du laver en kopi af. At starte replikering med kommandoen CHANGE MASTER TO ville se sådan ud:
mysql> CHANGE MASTER TO MASTER_HOST='x.x.x.x',MASTER_USER='replication_user', MASTER_PASSWORD='password', MASTER_LOG_FILE='master-bin.0001', MASTER_LOG_POS= 04;
At starte replikering på det forkerte sted kan have katastrofale konsekvenser:data kan være dobbeltskrevet eller ikke opdateret. Dette forårsager datadrift mellem master- og slaveknuden.
Også når man fejler over en master til en slave, involverer man at finde den korrekte position og ændre masteren til den passende vært. MySQL beholder ikke de binære logfiler og positioner fra sin master, men opretter snarere sine egne binære logfiler og positioner. For at genjustere en slaveknude til den nye master kan dette blive et alvorligt problem:masterens nøjagtige position ved failover skal findes på den nye master, og så kan alle slaver justeres igen.
For at løse dette problem er Global Transaction Identifier (GTID) blevet implementeret af både Oracle og MariaDB. GTID'er tillader automatisk justering af slaver, og i både MySQL og MariaDB finder serveren selv ud af, hvad den korrekte position er. Begge har dog implementeret GTID på en anden måde og er derfor inkompatible. Hvis du har brug for at konfigurere replikering fra den ene til den anden, skal replikeringen konfigureres med traditionel binær logpositionering. Også din failover-software skal gøres opmærksom på ikke at gøre brug af GTID'er.
Konklusion
Vi håber at have givet dig nok tips til at holde dig ude af problemer. Disse er alle almindelige fremgangsmåder fra eksperterne i MySQL. De skulle lære det på den hårde måde, og med disse tips sikrer vi, at du ikke behøver det.
Vi har nogle yderligere hvidbøger, som kan være nyttige, hvis du gerne vil læse mere om MySQL-replikering.
Relaterede whitepapers MySQL-replikerings-blueprintMySQL-replikerings-blueprint-hvidbogen omfatter alle aspekter af en replikeringstopologi med ins og outs af implementering, opsætning af replikering, overvågning, opgraderinger, udførelse af sikkerhedskopier og styring af høj tilgængelighed ved hjælp af proxyer.Download MySQL-replikering for høj tilgængelighedDenne vejledning dækker oplysninger om MySQL-replikering, med information om de seneste funktioner introduceret i 5.6 og 5.7. Der er også et mere praktisk, praktisk afsnit om, hvordan man hurtigt implementerer og administrerer en replikeringsopsætning ved hjælp af ClusterControl.Download