Migrering af MySQL 5 til MySQL 8

Her kan du læse hvordan vi gennemførte en migrering af en stor MySQL 5 database til MySQL 8 med minimal nedetid, fuldt roll-back scenarie og fuld backup hele vejen.

Der er en række fordele ved MySQL 8 fremfor MySQL 5. Hos Overskrift havde vi brug for en del af disse fordele. Vi var også ved at slå hovedet mod loftet i de begrænsninger, der er indbygget i den aldrende MyISAM tabeltype.

Når databasecrashes begynder at blive en tilbagevendende begivenhed, er det på tide at stoppe op. I “gamle dage” (MySQL 5.5) understøttede tabeltypen InnoDB ikke full-text indexes, så vi havde en del data gemt i MyISAM-tabeller. Det viste sig problematisk ved store datamængder der ofte voksede, blev opdateret og slettet. Da planlægningen startede, var tanken at migrere til MySQL version 5.7, da MySQL 8 var meget ny på daværende tidspunkt.

Samtidig researchede vi fritekst-søgeteknologier og endte med at alle data skulle migreres til MySQL 8. Den tunge fritekst-søgning skulle dog foregå på ElasticSearch fremadrettet – en gennemprøvet, men dog ny teknologi for os. Søgninger der tidligere kunne tage flere sekunder med MySQL tog et tilsvarende antal millisekunder i ElasticSearch. Den svære del af øvelsen var, at migrere det hele uden nedetid.

Hvad der ikke virkede

Vi har arbejdet en del med database backup via MySQL replikering; En process der registrerer alle loggede dataopdateringer og lader en anden MySQL database læse og udføre de samme opdateringer. Det forudsætter at begge databaser har et fælles udgangspunkt – f.eks. et databasedump fra originaldatabasen. På den måde har vi en backup af databasen kørende (slave), som maksimalt er få sekunder bagud fra originaldatabasen (master). Hvis vi kunne lave en komplet kopi af MySQL 5.5 databasen, ville vi altså kunne replikere den til MySQL 8. Derefter består skiftet i en simpel opdatering af databasens DNS-registrering.

MEN replikering virker kun med maksimalt en en minor version i afvigelse. Replikering fra version 5.5 til 5.6 er OK, men version 5.5 til 5.7 er no-go. Vi skulle altså etablere en kæde fra MySQL 5.5 til 5.6 til 5.7 til MySQL 8.0. Replikering mellem databaser af forskellig version er også mere følsom overfor små versions-afhængige afvigelser (og skulle håndbæres og genstartes ofte). Denne fremgangsmåde hjalp os heller ikke af med de aldrende MyISAM tabeller.

Normal kan MySQL selv opdatere data-filerne fra en tidligere version, hvis man bare kopierer dem ind i den korrekte data-folder. Succesraten falder når man springer over flere minor versioner. Så er vi tilbage ved at skulle producere en kæde af MySQL servere, der kan håndtere datafiler. Det er heller ikke muligt at beregne, hvor lang tid datamigreringen i så fald ville tage.

Alt i alt var selve processen overtænkt, og endte med at være usikker fordi den var kompliceret. Vi valgte at skrue ned for kompleksiteten.

Kravene til migrering af MySQL databasen

  • Der måtte ikke findes MyISAM tabeller i databasen efter opdateringen, så alle MyISAM tabeller skulle konverteres til InnoDB
  • Data der var fulltext-indekseret skulle kopieres til ElasticSearch
  • Nedetiden skulle holdes på et minimum. Tests forud for den rigtige migrering skulle godtgøre at migreringen var mulig at gennemføre under et præcist estimat.

Forberedelser

Den nye produktionsdatabase skal have en backup-server klar, som vi hele tiden kan anvende i tilfælde af nedbrud. Ligesom tidligere, har vi en langsommere og billigere server klar til at overtage, hvis den nye produktionsdatabase skulle gå ned. Den kører samme version (8) af MySQL og replikerer fra produktionsserveren. Det var vigtigt at den også replikerede før migreringsprocessen, så vi dermed fik eftervist at den kunne følge med. Hvis master serveren er for hurtigt i forhold til slaven (ja – det kalder man det), kan den komme langt bagud. Det er faktisk muligt at den er så langsom at den ikke kan følge med, og at replikeringstiden aldrig falder. I sådanne tilfælde vil backup serveren være ubrugelig, og skal bestykkes med hurtigere diske og mere RAM.

Replikeringsserveren var i gang med at replikere fra produktionsserveren, selv før tabellerne var oprettet på den nye produktionsserver. Derved kunne vi blot kaste et blik på backupserveren en gang imellem, og observere at replikeringstiden faldt.

Hvad der virkede

Vi endte med at script’e alt, så oprettelser og dataoverførsler var automatiserede. Scripts blev produceret ved heftig brug af mysqldump-kommandoen og opdelt i 4 “klumper”:

  1. Tabel-strukturer uden indexes (produceres i god tid før migrering)
  2. Data fra alle tabeller (produceres ca. et døgn før migreringen)
  3. Nye data (delta) fra tabeller med høj opdateringsfrekvens (produceres under migrering)
  4. Index-oprettelse på tabellerne (produceres i god tid før migreringen, køres på ny database når alle data er overført)

Oprettelsen af alle tabellers strukturer (pkt. 1) går stærkt (få sekunder), og kan afvikles på den nye database forud for migreringen. Inden den afvikles omskrives alle forekomster af MyISAM til InnoDB. Dermed er strukturen på plads med de korrekte tabeltyper.

Data blev dumpet fra den gamle MySQL 5 server (pkt. 2) og streamet via netværket direkte til MySQL 8-serveren. Mål-serveren er desuden bestykket med SSD-disks i RAID, mens den gamle server havde fysiske (dog stadig hurtige diske i RAID). Denne dataoverførsel var den største og varede længst – ca. 10 timer, hvilket er en hel del når man tænker på at det er rå data, som endnu ikke er indekseret, der blev sendt over netværket. Rationalet var at data, så tidligt som muligt, skulle flyttes til den nye produktionsserver, da ydelsen af SSD-diskene på den nye server gjorde den nye database mange faktorer hurtigere end den gamle server og at behandling af større datamængder i processen altid skulle ske her.

Delta-scriptet var det mest komplicerede. For alle tabeller undersøgte det de maksimale id’er på alle tabellerne, og kunne derfor nøjes med at kopiere evt. nye data over netværket til de nye tabeller med almindelige INSERT-statements. Delta-scriptet kunne køres igen og igen, og jo kortere intervaller det blev afviklet med, desto hurtigere var data fuldt opdaterede på mål-serveren. Delta-scriptet var ca. 2 timer om at overføre et døgns data-delta, så kørt før migreringen af MySQL blev sat i gang, blev scriptet kørt, for på den måde at minimere nedetiden under selve migreringen.

Migreringsplanen blev nedskrevet punkt for punkt med estimater for hvert punkt, og var gennemført flere gange før den skarpe migrering af MySQL databasen.

Selve migreringen bestod altså (let forsimplet) af at:

  1. lukke alle services ned, som anvendte databasen
  2. køre delta-scriptet igen (denne gang tog det kun ca. 10 minutter, da data-bevægelserne var meget begrænsede)
  3. køre index-scriptet til oprettelse af indexes på mål-databasen (hvilket tog ca. en halv time, da vi havde fjernet alle komplekse full-text indexes)
  4. rette dns-registreringen for databasen
  5. genstarte alle services

I alt blev den store database migreret med en samlet nedetid på ca. 45 minutter, selvom den største del af data tog mere end 10 timer at flytte.

Roll-back planen

For hvert trin i migreringsprocessen blev der ligeledes nedskrevet et eller flere roll-back trin, således at det samlede system hurtigt kan komme tilbage i produktion på den gamle server. I dette tilfælde drejede det sig dog primært om at starte services op igen, før rettelsen i dns-registreringen.

Konklusion

Forud for migreringen anvendte vi replikeringsteknologier, forsøgte at ændre tabeltyper på MyISAM-tabeller, der var vel belæsset med data. Vi kunne ikke rigtig se hvordan vi kunne klare os uden de håndjern som MySQL 5.5 og dermed MyISAM-kravet for at understøtte fulltext-indexes, men der opstod en vis forløsning da vi begyndte at insistere på at forsimple processen.

MySQL logger ikke noget videre forståeligt, når den først crasher, men ved at tilvælge udelukkende at bruge den nyeste og mest stabile tabel type, og ved at flytte fritekst-søgning væk fra den relationelle database, som til gengæld er god til nøgle-indekserede tabeller, fik vi sænket kompleksiteten. I sidste ende betød det, at vi kunne designe en migreringsproces, som var replikérbar, som kunne estimeres ret præcist og som kunne rulles tilbage hvis noget skulle vise sig at gå galt.

I et andet indlæg beskriver jeg migreringen af data til ElasticSearch.


Har du brug for hjælp til migrering af MySQL databaser? Læs evt. hvilke andre teknologier vi har mest erfaring med.

Ring til Jens Ulrik på 21 24 88 85 eller skriv en e-mail til jul@nuit.dk.