Under de senaste månaderna har jag arbetat med onlineuppgradering för mycket stora databaser som en del av AXLE-projektet och jag skulle vilja dela med mig av mina tankar om ämnet och vilka framsteg vi har gjort nyligen.
Innan jag gick med i 2ndQuadrant arbetade jag i Skype där företaget inte tillät ett underhållsfönster för våra databaser. Detta innebar att ingen stilleståndstid tilläts för distributioner, uppgraderingar, etc. Den typen av regel gör att du ändrar sättet du gör saker på. De flesta ändringar är små, du gör inga tunga lås, du har repliker för att möjliggöra snabb fail-over. Men även om du kan göra dina utgåvor små och icke-blockerande, vad händer när du behöver göra en större versionsuppgradering av PostgreSQL-databasen?
Du kan vara i en annan situation, eftersom de flesta företag har ett uppgraderingsfönster, och du kan därför ha råd med lite stillestånd under uppgraderingen. Detta medför dock två problem. För det första gillar inget företag faktiskt stilleståndstiderna även om de är tillåtna. Och ännu viktigare när din databas växer bortom gigabyte i storlek och in i intervallet av terabyte eller hundratals terabyte, kan driftstoppet ta dagar eller till och med veckor och ingen har råd att stoppa sin verksamhet så länge. Resultatet är att många företag ofta hoppar över viktiga uppgraderingar, vilket gör nästa faktiskt ännu mer smärtsam. Och utvecklarna saknar nya funktioner, prestandaförbättringar. De (företagen) riskerar ibland till och med att köra en PostgreSQL-version som inte längre stöds och som har kända datakorruption eller säkerhetsproblem. I de följande styckena kommer jag att prata lite om mitt arbete med att göra uppgraderingarna mindre tidskrävande och som ett resultat mindre smärtsamma och förhoppningsvis mer frekventa.
Låt mig börja med lite historia först. Före PostgreSQL 9.0 var det enda sättet att göra en större versionsuppgradering att köra pg_dump och återställa dumpen till en instans som körde en nyare version av PostgreSQL. Denna metod krävde att strukturen och all data lästes från databasen och skrevs in i en fil. Läs sedan från filen och infogas i en ny databas, index måste byggas om osv.
Som du kan föreställa dig kan denna process ta ganska lång tid. Förbättringar av prestanda gjordes i 8.4 för pg_restore med alternativet -j tillagt där du kan specificera hur många parallella jobb som ska köras. Detta gör det möjligt att återställa flera tabeller (index, etc) parallellt vilket gör återställningsprocessen snabbare för anpassade formatdumpar. 9.3-versionen lade till liknande alternativ till pg_dump, vilket förbättrade prestandan ytterligare. Men med tanke på hur snabbt datavolymerna växer, är parallelliseringen i sig inte tillräcklig för att göra någon allvarlig vinst på den tid som krävs för uppgradering.
Sedan kom ett verktyg som heter pg_upgrade i PostgreSQL 9.0. Pg_upgrade dumpar bara strukturerna och återställer dem till det nya klustret. Men den kopierar datafilerna som de finns på disken, vilket är mycket snabbare än att dumpa dem i logiskt format och sedan återinsätta. Detta är tillräckligt bra för små databaser eftersom det innebär en stilleståndstid inom intervallet minuter eller timmar, en tid som är acceptabel för många scenarier. Det finns också länkläget som bara skapar hårda länkar (övergångspunkter på Windows) vilket gör denna process ännu snabbare. Men ur min personliga synvinkel är det för farligt att köra en sådan installation på en produktionsmasterserver. Jag ska kort förklara varför. Om något går fel, när du väl startar din nya server som har uppgraderats med länkläget, är du plötsligt utan produktionsdatabas och måste göra en fail-over, eller ännu värre, du måste återställa från backup. Det betyder att du inte bara misslyckades med att uppgradera utan att du bara orsakade ytterligare driftstopp! Lycka till med att få godkännande nästa gång.
Nu använder många människor som inte har råd med långa stilleståndstider för uppgraderingar triggerbaserade replikeringslösningar som Slony eller Londiste för att göra uppgraderingen. Detta är en bra lösning eftersom du kan replikera dina data medan den ursprungliga servern körs och sedan byta med minimal driftstopp. I praktiken finns det dock flera problem. En av dem är att de triggerbaserade lösningarna ofta är klumpiga att installera, speciellt om du bara gör det en gång vartannat år och bara för att göra uppgraderingen. Det är också lätt att missa ett bord eller lägga till tabeller i fel ordning och därmed inte få hela exemplaret. Jag har sett detta i praktiken och personer som gjorde uppgraderingen arbetade med den triggerbaserade replikeringen dagligen . Ett annat problem är att de triggerbaserade lösningarna lägger till avsevärd belastning på källdatabasen, vilket ibland gör uppgraderingen omöjlig på grund av att databasservern blir överbelastad när replikeringen väl har aktiverats. Och sist men ofta inte minst kan det ta väldigt lång tid för den triggerbaserade replikeringen att faktiskt flytta data till den nya servern. Vid det senaste tillfället jag var involverad i ett uppgraderingsprojekt tog den triggerbaserade lösningen ungefär en månad att kopiera databasen och komma ikapp med ändringar. Ja, en månad.
Med PostgreSQL 9.4 kommer den logiska avkodningsfunktionen som erbjuder en nystart för att designa en ny och bättre onlineuppgraderingsproblemlösning. Vad vi gjorde, som en del av AXLE-projektet, är att skapa ett verktyg som kombinerar den logiska avkodningen med de tekniker som beskrivs ovan. Lösningen löser de flesta problemen med tidigare tillvägagångssätt. Uni-Directional Replication PostgreSQL-tillägget (UDR för kort) gör logisk replikering med hjälp av logisk avkodning av WAL (Write Ahead-loggen). Tack vare detta är effekten på masterservern nästan i nivå med den fysiska streamingreplikeringen, så den extra belastningen som orsakas av pågående uppgradering är minimal på det körande systemet. Det ger också verktyg för att initiera nya noder, både med fysisk och logisk säkerhetskopiering. Du kan till och med ställa om befintligt fysiskt standbyläge till UDR-standby. Och eftersom det är ett logiskt replikeringssystem är det möjligt att designa det på ett sätt som stöder replikering över flera versioner.
Vad allt detta betyder är att vi nu kan använda UDR i kombination med pg_upgrade för att göra en onlineuppgradering av större PostgreSQL-versioner med minimal stilleståndstid, på kort tid och med minimal påverkan på det körande systemet.
Ett exempel på hur detta kan se ut i praktiken:
- Gör pg_basebackup av befintlig instans.
- Ställ in UDR-replikeringen mellan den ursprungliga instansen och den som skapades av basebackup.
- Pg_uppgradera den nya instansen.
- Låt UDR spela upp ändringarna som skedde under tiden.
- Byt trafiken till den nya instansen.
För hur man gör med mer detaljerade instruktioner, se UDR Online Upgrade guide på PostgreSQL wiki. UDR-källorna är tillgängliga i 2ndquadrant_bdr-förrådet på PostgreSQL git-servern (bdr-plugin/next branch).
Slutligen, eftersom UDR inte bara är ett onlineuppgraderingsverktyg utan också en replikeringslösning, kan det användas för dina vanliga replikeringsbehov, istället för den fysiska strömmande replikeringen. Dessutom ger det flera fördelar som möjligheten att skapa temporära tabeller, replikera från flera OLTP-databaser till en databas för stora datalager, eller replikera bara en del av databasen.
Min förhoppning är att denna ansträngning kommer att innebära att överväganden om stillestånd inte längre är ett problem när det gäller att uppgradera från PostgreSQL 9.4 och senare till en ny större version.
Den forskning som leder till dessa resultat har fått finansiering från Europeiska unionens sjunde ramprogram (FP7/2007-2013) under bidragsavtal nr 318633.