MariaDB replikering: Når replikeringen fejler

(Last Updated On: 2. marts 2018)

Hvad er problemet?

Du har sikkert opdaget at din slave ikke længere replikerer ved at kigge på SHOW SLAVE STATUS, her et eksempel:

  • Slave_SQL_Running er “No”, den skal naturligvis helst stå til “Yes”.
  • Seconds_Behind_Master er “NULL”. Her skal der altid stå et tal.
  • Slave_SQL_Running_State bør ikke være tom.

Derudover er der i SHOW SLAVE STATUS også  information om IO og SQL fejl:

  • Last_Error
  • Last_Errno
  • Last_IO_Error
  • Last_IO_Errno
  • Last_SQL_Error
  • Last_SQL_Errno

Hvis ovenstående felter er tomme, skal du kigge i fejlloggen, der som regel ligger under /var/log/mysql/error.log.

Eksempler på fejl

Her er det gået grueligt galt. Slaven er kommet så langt bagud, at den ikke kan indhente det tabte:

Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: ‘Could not find GTID state requested by slave in any binlog files. Probably the slave state is too old and required binlog files have been purged.’

Her er et par mindre fatale sql fejl. Når det opdages i tide, er det forholdsvist nemt at fikse.

På min master har jeg konfigureret at phpmyadmin databasen IKKE skal med i de binære logfiler. Men PhpMyAdmin har en kedelig uhensigtsmæssighed. Den glemmer at udføre USE phpmyadmin; før den arbejder med data. Derfor havner disse queries alligevel i loggen og læses af min slave… og da phpmyadmin databasen ikke eksisterer på min slave, fejler den:

Last_SQL_Errno: 1146
Last_SQL_Error: Error ‘Table ‘phpmyadmin.pma_recent’ doesn’t exist’ on query. Default database: ”. Query: ‘REPLACE INTO phpmyadmin.pma_recent (username, tables) […]

Her er der et cronjob der tilsyneladene har en fejl et sted. I hvert fald forsøger den sig med en INSERT der forårsager en “Duplicate entry”:

Last_SQL_Errno: 1062
Last_SQL_Error: Error ‘Duplicate entry ‘131954’ for key ‘PRIMARY” on query. Default database: ‘shop_live’. Query: ‘INSERT INTO Total (id, blocked, filtered) VALUES(‘131954′,’2′,0)’

Her forsøges opdateret en række, der ikke findes på slaven:

Last_SQL_Errno: 1032
Last_SQL_Error: Could not execute Update_rows_v1 event on table shop_live.StatusDate; Can’t find record in ‘StatusDate’ […]

Nedenstående fejl har jeg oplevet 2 gange, hvor det begge gange var slavens binære log der var blevet korrupt. Læs mere her: MariaDB replikering: Korrupt binær log på slave

Last_SQL_Errno: 1594
Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master’s binary […]

Det hurtige fiks

Når replikeringen stopper pga SQL fejl, kan du forsøge dig med at springe et par queries over. Den her virker for mig i de fleste tilfælde:

Hvis det ikke virker i første omgang, så prøv at forøge tallet. I ovennævnte eksempel vil replikeringen ignorere de 2 næste queries og derefter fortsætte som normalt. Slaven vil i løbet af kort tid indhente det forsømte. Se efter Seconds_Behind_Master som gerne skulle gå i 0 efter lidt tid.  Skip_Counter fortæller hvor mange queries den mangler at skippe. Men med så lavt et talt som 2, vil den meget hurtig gå i 0 igen.

Hvis der er fejl du ikke ønsker skal stoppe din replikering, kan du sætte slave-skip-errors i my.cnf. Her angiver du fejlkode(r) efter behov. Du kan se fejlkoden ud for Last_*_Errno i output fra SHOW SLAVE STATUS\G. Flere koder adskilles med komma:

Men pas på. Fejl er indikationer på at der er noget galt i et eller andet program/script/job der kommunikerer med databasen, og bør derfor ikke ignoreres medmindre du ved hvad du gør.

Slavens status viser ingen fejlmeddelelser

Hvis der ikke er nogen fejlmeddelelser at se i output fra SHOW SLAVE STATUS skal du kigge i fejlloggen (som regel /var/log/mysql/error.log). Her et eksempel:

Slaven kan af en eller anden årsag ikke læse sin egen logfil og vi skal derfor tvinge den til at oprette en ny. Notér værdierne fra følgende felter i SHOW SLAVE STATUS\G:

  • Relay_Master_Log_File
    den binære log på masteren som slaven er igang med at læse fra
  • Exec_Master_Log_Pos
    den position i ovenstående log slaven skal starte fra

Start med at nulstille slaven. Dette tvinger den til at oprette en ny logfil. Normalt vil man udføre en STOP SLAVE kommando først, men i dette tilfælde er slaven allerede stoppen pga. fejlen:

Nu er slaven nulstillet, og vi skal derfor fortælle den hvorfra den skal starte. Erstat værdierne i nedenstående med ovennævnte:

 

Hvis det er helt galt

Når noget er gået helt galt og din slave er kommet så langt bagud, at det er håbløst at fikse, må du starte forfra. Det er ofte tilfældet når du støder på en Last_IO_Error.

Find et tidspunkt hvor ingen vigtige cronjobs kører og der er færrest brugere på systemet. Din master vil nemlig blive låst for både læsning og skrivning mens vi laver en backup.

Master

Log på din master server. Lås den og notér dig herefter masterens position:

Eksempel:

Du må IKKE forlade din mysql prompt da dette vil frigøre din lås. Log derfor på i en anden session og lav din backup:

Det er vigtigt at du i ovenstående kun udvælger de databaser der normalt skrives til dine binære logfiler.

Gå derefter tilbage i din første session, og lås op igen:

Nu er der igen adgang og alt kører som normalt.

Kopiér dit dump til slaven, evt via scp:

Nu er vi færdige med din master.

Slave

Log ind på din slave som nu skal stoppes og nulstilles:

I en anden session, kan du nu indlæse data fra masteren:

Ovenstående kan tage laaaaaang tid, afhængig af hvor meget data filen indeholder. Det tog mig omkring ½ time at indlæse en fil på 7GB. Hvis du er i tvivl om der overhovedet sker noget, så prøv at logge på databasen i en anden session og kør SHOW PROCESSLIST et par gange for at se at output ændrer sig.

Nu skal vi fortælle slaven fra hvilket tidspunkt den skal opdatere. Vi ændrer derfor filnavn og position med CHANGE_MASTER_TO og starter derefter slaven igen:

Tjek status og se at alt kører som det skal: