Att ställa in replikering i MySQL är enkelt, men att hantera det i produktionen har aldrig varit en lätt uppgift. Även med den nyare GTID-autopositioneringen kan det fortfarande gå fel om du inte vet vad du gör. Efter att ha ställt in replikering kan alla möjliga saker gå fel. Misstag kan lätt göras och kan få ett katastrofalt slut på din data.
Det här inlägget kommer att belysa några av de vanligaste misstagen som görs med MySQL-replikering och hur du kan förhindra dem.
Ställa in replikering
När du ställer in MySQL-replikering måste du prima slavnoderna med datamängden från mastern. Med lösningar som Galera kluster hanteras detta automatiskt åt dig med den metod du väljer. För MySQL-replikering måste du göra detta själv, så du tar naturligtvis ditt standardverktyg för säkerhetskopiering.
För MySQL finns det ett stort utbud av säkerhetskopieringsverktyg, men det vanligaste är mysqldump. Mysqldump matar ut en logisk säkerhetskopia av din masters datauppsättning. Detta betyder att kopian av data inte kommer att vara en binär kopia, utan en stor fil som innehåller frågor för att återskapa din datauppsättning. I de flesta fall bör detta ge dig en (nästan) identisk kopia av dina data, men det finns fall där det inte gör det - på grund av att dumpningen sker per objekt. Det betyder att även innan du börjar replikera data är din datauppsättning inte densamma som den på mastern.
Det finns ett par tweaks du kan göra för att göra mysqldump mer tillförlitlig som dump som en enda transaktion, och glöm inte att inkludera rutiner och triggers:
mysqldump -uuser -ppass --single-transaction --routines --triggers --all-databases > dumpfile.sql
En bra praxis är att kontrollera om din slavnod är 100 % densamma, är att använda pt-table-checksum efter att du har ställt in replikeringen:
pt-table-checksum --replicate=test.checksums --ignore-databases mysql h=localhost,u=user,p=pass
Detta verktyg kommer att beräkna en kontrollsumma för varje tabell på mastern, replikera kommandot till slaven och sedan kommer slavnoden att utföra samma kontrollsummaoperation. Om någon av tabellerna inte är densamma bör detta synas tydligt i kontrollsummatabellen.
Använder fel replikeringsmetod
Standardreplikeringsmetoden för MySQL var den så kallade satsbaserade replikeringen. Den här metoden är precis vad den är:en replikeringsström av varje sats som körs på mastern som kommer att spelas upp på slavnoden. Eftersom MySQL i sig är flertrådad men den (traditionella) replikeringen inte är det, kanske ordningen på uttalanden i replikeringsströmmen inte är 100 % densamma. Att spela om ett uttalande kan också ge olika resultat när det inte körs på exakt samma tid.
Detta kan resultera i olika datamängder mellan master och slav, på grund av datadrift. Detta var inte ett problem på många år, eftersom inte många körde MySQL med många samtidiga trådar, men med moderna multi-CPU-arkitekturer har detta faktiskt blivit mycket troligt under en normal daglig arbetsbelastning.
Svaret från MySQL var den så kallade radbaserade replikeringen. Radbaserad replikering kommer att replikera data när det är möjligt, men i vissa undantagsfall används fortfarande uttalanden. Ett bra exempel skulle vara DLL-ändringen av en tabell, där replikeringen sedan skulle behöva kopiera varje rad i tabellen genom replikering. Eftersom detta är ineffektivt kommer ett sådant uttalande att replikeras på traditionellt sätt. När radbaserad replikering upptäcker datadrift stoppar den slavtråden för att förhindra att saker och ting blir värre.
Sedan finns det en metod mellan dessa två:mixed mode replikering. Denna typ av replikering kommer alltid att replikera satser, förutom när frågan innehåller funktionen UUID() används triggers, lagrade procedurer, UDF:er och några andra undantag. Blandat läge löser inte problemet med datadrift och bör undvikas tillsammans med uttalandebaserad replikering.
Cirkulär replikering
Att köra MySQL-replikering med multi-master är ofta nödvändigt om du har en multi-datacentermiljö. Eftersom applikationen inte kan vänta på att mastern i det andra datacentret ska bekräfta din skrivning, är en lokal master att föredra. Normalt används den automatiska inkrementförskjutningen för att förhindra datakrockar mellan masterna. Att låta två master utföra skrivningar till varandra på detta sätt är en allmänt accepterad lösning.
MySQL Master-Master replikeringMen om du behöver skriva i flera datacenter i samma databas, slutar du med flera masters som behöver skriva sina data till varandra. Innan MySQL 5.7.6 fanns det ingen metod för att göra en mesh-typ av replikering, så alternativet skulle vara att använda en cirkulär ringreplikering istället.
MySQL ringreplikeringstopologiRingreplikering i MySQL är problematisk av följande skäl:latens, hög tillgänglighet och datadrift. Att skriva lite data till server A skulle ta tre hopp för att hamna på server D (via server B och C). Eftersom (traditionell) MySQL-replikering är entrådig, kan alla långa frågor i replikeringen stoppa hela ringen. Även om någon av servrarna skulle gå ner, skulle ringen brytas och för närvarande finns det ingen failover-mjukvara som kan reparera ringstrukturer. Då kan datadrift uppstå när data skrivs till server A och ändras samtidigt på server C eller D.
Bruten ringreplikeringI allmänhet är cirkulär replikering inte en bra passform med MySQL och det bör undvikas till varje pris. Galera skulle vara ett bra alternativ för multi-datacenterskrivningar, eftersom det har utformats med det i åtanke.
Stanna din replikering med stora uppdateringar
Ofta kommer olika hushållsbatch-jobb att utföra olika uppgifter, allt från att rensa upp gamla data till att beräkna medelvärden av "gilla" hämtade från en annan källa. Detta innebär att med bestämda intervaller kommer ett jobb att skapa mycket databasaktivitet och, med största sannolikhet, skriva mycket data tillbaka till databasen. Naturligtvis innebär detta att aktiviteten inom replikeringsströmmen kommer att öka lika mycket.
Statement-baserad replikering kommer att replikera de exakta frågorna som används i batchjobben, så om frågan tog en halvtimme att bearbeta på mastern, kommer slavtråden att stoppas under minst samma tid. Detta betyder att ingen annan data kan replikera och slavnoderna kommer att börja släpa efter mastern. Om detta överskrider tröskeln för ditt failover-verktyg eller proxy, kan det ta bort dessa slavnoder från de tillgängliga noderna i klustret. Om du använder satsbaserad replikering kan du förhindra detta genom att krossa data för ditt jobb i mindre omgångar.
Nu kanske du tror att radbaserad replikering inte påverkas av detta, eftersom det kommer att replikera radinformationen istället för frågan. Detta är delvis sant, eftersom för DDL-ändringar återgår replikeringen till ett uttalandebaserat format. Ett stort antal CRUD-operationer kommer också att påverka replikeringsströmmen:i de flesta fall är detta fortfarande en enstaka trådad operation och därför kommer varje transaktion att vänta på att den föregående ska spelas om via replikering. Detta betyder att om du har hög samtidighet på mastern, kan slaven stanna vid överbelastningen av transaktioner under replikering.
För att komma runt detta erbjuder både MariaDB och MySQL parallell replikering. Implementeringen kan skilja sig åt per leverantör och version. MySQL 5.6 erbjuder parallell replikering så länge frågorna är åtskilda av schema. MariaDB 10.0 och MySQL 5.7 kan båda hantera parallell replikering över scheman, men har andra gränser. Att köra frågor via parallella slavtrådar kan påskynda din replikeringsström om du skriver tungt. Men om du inte är det, skulle det vara bäst att hålla sig till den traditionella enkelgängade replikeringen.
Schemaändringar
Att utföra schemaändringar på en pågående produktionsinstallation är alltid jobbigt. Detta har att göra med det faktum att en DDL-ändring för det mesta kommer att låsa en tabell och bara släppa detta lås när DDL-ändringen har tillämpats. Det blir till och med värre när du börjar replikera dessa DDL-ändringar genom MySQL-replikering, där det dessutom kommer att stoppa replikeringsströmmen.
En ofta använd lösning är att först tillämpa schemaändringen på slavnoderna. För satsbaserad replikering fungerar detta bra, men för radbaserad replikering kan detta fungera upp till en viss grad. Radbaserad replikering tillåter att extra kolumner finns i slutet av tabellen, så så länge den kan skriva de första kolumnerna går det bra. Tillämpa först ändringen på alla slavar, sedan failover på en av slavarna och tillämpa sedan ändringen på mastern och anslut den som en slav. Om din ändring innebär att du infogar en kolumn i mitten eller tar bort en kolumn kommer detta att fungera med radbaserad replikering.
Det finns verktyg runt omkring som kan utföra onlineschemaändringar mer tillförlitligt. Percona Online Schema Change (som kallas pt-osc) kommer att skapa en skuggtabell med den nya tabellstrukturen, infoga ny data via triggers och återfyllningsdata i bakgrunden. När det är klart att skapa den nya tabellen, kommer den helt enkelt att byta ut den gamla mot den nya tabellen i en transaktion. Detta fungerar inte i alla fall, särskilt om din befintliga tabell redan har utlösare.
Ett alternativ är det nya Gh-ost-verktyget från Github. Detta online-schemaändringsverktyg kommer först att göra en kopia av din befintliga tabelllayout, ändra tabellen till den nya layouten och sedan koppla upp processen som en MySQL-replik. Den kommer att använda sig av replikeringsströmmen för att hitta nya rader som har infogats i den ursprungliga tabellen och samtidigt fyller den ut tabellen. När återfyllningen är klar kommer de ursprungliga och nya tabellerna att bytas. Naturligtvis kommer alla operationer till den nya tabellen också att hamna i replikeringsströmmen, så på varje replik sker migreringen samtidigt.
Minnestabeller och replikering
Medan vi är på ämnet DDL, är ett vanligt problem skapandet av minnestabeller. Minnestabeller är icke-beständiga tabeller, deras tabellstruktur finns kvar men de förlorar sina data efter en omstart av MySQL. När du skapar en ny minnestabell på både en master och en slav kommer båda att ha en tom tabell och detta kommer att fungera perfekt. När någon av dem har startat om kommer tabellen att tömmas och replikeringsfel kommer att uppstå.
Radbaserad replikering kommer att gå sönder när data i slavnoden ger olika resultat, och satsbaserad replikering kommer att gå sönder när den försöker infoga data som redan finns. För minnestabeller är detta en frekvent replikeringsbrytare. Fixningen är enkel:gör helt enkelt en ny kopia av data, ändra motorn till InnoDB och den borde nu vara replikeringssäker.
Ställa in den skrivskyddade variabeln till True
Som vi beskrev tidigare, kan inte ha samma data i slavnoderna bryta replikeringen. Ofta har detta orsakats av att något (eller någon) ändrat data på slavnoden, men inte på masternoden. När masternodens data har ändrats, kommer detta att replikeras till slaven där den inte kan tillämpa ändringen och detta gör att replikeringen bryts.
Det finns ett enkelt förhindrande för detta:ställ in variabeln read_only till true. Detta kommer att förbjuda någon att göra ändringar i data, förutom för replikering och root-användare. De flesta failover-hanterare ställer in denna flagga automatiskt för att förhindra användare att skriva till den använda mastern under failover. Vissa av dem behåller till och med detta efter failover.
Detta lämnar fortfarande rotanvändaren att utföra en felaktig CRUD-fråga på slavnoden. För att förhindra att detta händer finns det en super_read_only-variabel sedan MySQL 5.7.8 som till och med låser rotanvändaren från att uppdatera data.
Aktivera GTID
I MySQL-replikering är det viktigt att starta slaven från rätt position i de binära loggarna. Att erhålla denna position kan göras när du gör en säkerhetskopia (xtrabackup och mysqldump stödjer detta) eller när du har slutat slava på en nod som du gör en kopia av. Att starta replikering med kommandot CHANGE MASTER TO skulle se ut så här:
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;
Att starta replikering på fel plats kan få katastrofala konsekvenser:data kan skrivas dubbelt eller inte uppdateras. Detta orsakar datadrift mellan mastern och slavnoden.
När misslyckas över en master till en slav innebär det också att hitta rätt position och byta master till lämplig värd. MySQL behåller inte binära loggar och positioner från sin master, utan skapar snarare sina egna binära loggar och positioner. För att justera om en slavnod till den nya mastern kan detta bli ett allvarligt problem:masterns exakta position vid failover måste hittas på den nya mastern, och sedan kan alla slavar justeras om.
För att lösa detta problem har Global Transaction Identifier (GTID) implementerats av både Oracle och MariaDB. GTID tillåter automatisk justering av slavar, och i både MySQL och MariaDB räknar servern ut själv vad den korrekta positionen är. Men båda har implementerat GTID på ett annat sätt och är därför inkompatibla. Om du behöver ställa in replikering från en till en annan, bör replikeringen ställas in med traditionell binär loggpositionering. Även din failover-programvara bör göras medveten om att inte använda GTID.
Slutsats
Vi hoppas ha gett dig tillräckligt med tips för att undvika problem. Dessa är alla vanliga metoder av experterna i MySQL. De var tvungna att lära sig det den hårda vägen och med dessa tips säkerställer vi att du inte behöver det.
Vi har några ytterligare vitböcker som kan vara användbara om du vill läsa mer om MySQL-replikering.
Relaterade whitepapers MySQL Replication Blueprint Whitepaper för MySQL Replication Blueprint inkluderar alla aspekter av en replikeringstopologi med in- och utlösningar för implementering, konfigurering av replikering, övervakning, uppgraderingar, säkerhetskopiering och hantering av hög tillgänglighet med hjälp av proxyservrar. Ladda ner MySQL Replication for High AvailabilityDenna handledning omfattar information om MySQL-replikering, med information om de senaste funktionerna som introducerades i 5.6 och 5.7. Det finns också ett mer praktiskt och praktiskt avsnitt om hur man snabbt distribuerar och hanterar en replikeringsinställning med ClusterControl.Download