sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur man uppgraderar PostgreSQL 11 till PostgreSQL 12 med noll driftstopp

Det mest intuitiva sättet att uppgradera databas som du kan tänka dig är att generera en replika i en ny version och utföra en failover av programmet i den, och faktiskt fungerar det perfekt i andra motorer. Med PostgreSQL var detta tidigare omöjligt på ett inbyggt sätt. För att utföra uppgraderingar behövde du tänka på andra sätt att uppgradera, som att använda pg_upgrade, dumpning och återställning, eller använda några tredjepartsverktyg som Slony eller Bucardo, alla har sina egna varningar. Detta beror på det sätt som PostgreSQL använde för att implementera replikering.

PostgreSQL-strömmande replikering (den vanliga PostgreSQL-replikeringen) är en fysisk replikering som replikerar ändringarna på en byte-för-byte-nivå och skapar en identisk kopia av databasen på en annan server. Den här metoden har många begränsningar när du tänker på en uppgradering, eftersom du helt enkelt inte kan skapa en replik i en annan serverversion eller ens i en annan arkitektur.

Sedan PostgreSQL 10 har den implementerat inbyggd logisk replikering som, till skillnad från fysisk replikering, kan replikera mellan olika huvudversioner av PostgreSQL. Detta öppnar naturligtvis en ny dörr för uppgraderingsstrategier.

I den här bloggen kommer vi att se hur du kan uppgradera din PostgreSQL 11 till PostgreSQL 12 utan stilleståndstid med hjälp av logisk replikering.

Logisk postgreSQL-replikering

Logisk replikering är en metod för att replikera dataobjekt och deras ändringar, baserat på deras replikeringsidentitet (vanligtvis en primärnyckel). Den är baserad på ett publicerings- och prenumerationsläge, där en eller flera prenumeranter prenumererar på en eller flera publikationer på en förlagsnod.

En publikation är en uppsättning ändringar som genereras från en tabell eller en grupp av tabeller (även kallad en replikeringsuppsättning). Noden där en publikation definieras kallas utgivare. Ett abonnemang är nedströmssidan av logisk replikering. Noden där en prenumeration definieras kallas abonnenten, och den definierar kopplingen till en annan databas och uppsättning publikationer (en eller flera) som den vill prenumerera på. Prenumeranter hämtar data från de publikationer de prenumererar på.

Logisk replikering är byggd med en arkitektur som liknar fysisk strömmande replikering. Det implementeras av "walsender" och "apply" processer. Walsender-processen startar logisk avkodning av WAL och laddar standardinsticksprogrammet för logisk avkodning. Insticksprogrammet omvandlar ändringarna som läses från WAL till det logiska replikeringsprotokollet och filtrerar data enligt publikationsspecifikationen. Data överförs sedan kontinuerligt med hjälp av strömmande replikeringsprotokoll till appliceringsarbetaren, som mappar data till lokala tabeller och tillämpar de individuella ändringarna allt eftersom de tas emot, i en korrekt transaktionsordning.

Logisk replikering börjar med att ta en ögonblicksbild av data i utgivarens databas och kopiera det till abonnenten. De initiala uppgifterna i de befintliga prenumererade tabellerna är ögonblicksbilder och kopieras i en parallell instans av en speciell typ av appliceringsprocess. Denna process kommer att skapa sin egen temporära replikeringsplats och kopiera befintliga data. När befintlig data har kopierats går arbetaren in i synkroniseringsläge, vilket säkerställer att tabellen förs upp till ett synkroniserat tillstånd med den huvudsakliga appliceringsprocessen genom att strömma alla ändringar som hände under den första datakopieringen med hjälp av standard logisk replikering. När synkroniseringen är gjord, återförs kontrollen av replikeringen av tabellen till huvudappliceringsprocessen där replikeringen fortsätter som vanligt. Ändringarna på utgivaren skickas till prenumeranten när de sker i realtid.

Hur man uppgraderar PostgreSQL 11 till PostgreSQL 12 med logisk replikering

Vi kommer att konfigurera logisk replikering mellan två olika huvudversioner av PostgreSQL (11 och 12), och naturligtvis, när du har fått detta att fungera, är det bara en fråga om att utföra en applikationsfelövergång till databas med den nyare versionen.

Vi kommer att utföra följande steg för att få logisk replikering att fungera:

  • Konfigurera utgivarnoden
  • Konfigurera prenumerantnoden
  • Skapa prenumerantanvändaren
  • Skapa en publikation
  • Skapa tabellstrukturen i prenumeranten
  • Skapa prenumerationen
  • Kontrollera replikeringsstatusen

Så låt oss börja.

På utgivarsidan kommer vi att konfigurera följande parametrar i postgresql.conf-filen:

  • lyssna_adresser: Vilken/vilka IP-adresser att lyssna på. Vi kommer att använda '*' för alla.
  • wal_level: Bestämmer hur mycket information som skrivs till WAL. Vi kommer att ställa in den på "logisk".
  • max_replication_slots :Anger det maximala antalet replikeringsplatser som servern kan stödja. Den måste ställas in på minst det antal prenumerationer som förväntas ansluta, plus en viss reserv för tabellsynkronisering.
  • max_wal_senders: Anger det maximala antalet samtidiga anslutningar från standby-servrar eller strömmande backupklienter. Den bör ställas in på minst samma som max_replication_slots plus antalet fysiska repliker som är anslutna samtidigt.

Tänk på att vissa av dessa parametrar krävde en omstart av PostgreSQL-tjänsten för att tillämpas.

Pg_hba.conf-filen måste också justeras för att tillåta replikering. Du måste tillåta replikeringsanvändaren att ansluta till databasen.

Så baserat på detta, låt oss konfigurera utgivaren (i detta fall PostgreSQL 11-servern) enligt följande:

postgresql.conf:

listen_addresses = '*'

wal_level = logical

max_wal_senders = 8

max_replication_slots = 4

​pg_hba.conf:

# TYPE  DATABASE        USER            ADDRESS                 METHOD

host     all     rep1     10.10.10.131/32     md5

Du måste ändra användaren (i detta exempel rep1), som kommer att användas för replikering, och IP-adressen 10.10.10.131/32 för IP-adressen som motsvarar din PostgreSQL 12-nod.

På abonnentsidan kräver det också att max_replication_slots ställs in. I det här fallet bör den ställas in på åtminstone antalet prenumerationer som kommer att läggas till abonnenten.

De andra parametrarna som också måste ställas in här är:

  • max_logical_replication_workers :Anger det maximala antalet logiska replikeringsarbetare. Detta inkluderar både appliceringsarbetare och tabellsynkroniseringsarbetare. Logiska replikeringsarbetare tas från poolen som definieras av max_worker_processes. Den måste ställas in på åtminstone antalet prenumerationer, återigen plus en viss reserv för tabellsynkroniseringen.
  • max_worker_processes :Ställer in det maximala antalet bakgrundsprocesser som systemet kan stödja. Den kan behöva justeras för att passa replikeringsarbetare, åtminstone max_logical_replication_workers + 1. Den här parametern kräver en PostgreSQL-omstart.

Du måste alltså konfigurera abonnenten (i detta fall PostgreSQL 12-servern) enligt följande:

postgresql.conf:

listen_addresses = '*'

max_replication_slots = 4

max_logical_replication_workers = 4

max_worker_processes = 8

Eftersom denna PostgreSQL 12 kommer att bli den nya primära noden snart, bör du överväga att lägga till parametrarna wal_level och archive_mode i detta steg för att undvika en ny omstart av tjänsten senare.

wal_level = logical

archive_mode = on

Dessa parametrar kommer att vara användbara om du vill lägga till en ny replik eller för att använda PITR-säkerhetskopior.

I utgivaren måste du skapa användaren som prenumeranten kommer att ansluta till:

world=# CREATE ROLE rep1 WITH LOGIN PASSWORD '*****' REPLICATION;

CREATE ROLE

Rollen som används för replikeringsanslutningen måste ha attributet REPLICATION. Åtkomst för rollen måste konfigureras i pg_hba.conf och den måste ha LOGIN-attributet.

För att kunna kopiera den initiala datan måste rollen som används för replikeringsanslutningen ha SELECT-behörigheten på en publicerad tabell.

world=# GRANT SELECT ON ALL TABLES IN SCHEMA public to rep1;

GRANT

Vi kommer att skapa publikation 1 i utgivarnoden, för alla tabeller:

world=# CREATE PUBLICATION pub1 FOR ALL TABLES;

CREATE PUBLICATION

Användaren som ska skapa en publikation måste ha CREATE-behörigheten i databasen, men för att skapa en publikation som publicerar alla tabeller automatiskt måste användaren vara en superanvändare.

För att bekräfta den skapade publikationen kommer vi att använda pg_publication-katalogen. Denna katalog innehåller information om alla publikationer som skapats i databasen.

world=# SELECT * FROM pg_publication;

-[ RECORD 1 ]+-----

pubname      | pub1

pubowner     | 10

puballtables | t

pubinsert    | t

pubupdate    | t

pubdelete    | t

pubtruncate  | t

Kolumnbeskrivningar:

  • pubnamn :Namn på publikationen.
  • pubägare :Ägare av publikationen.
  • publikbord :Om sant, inkluderar denna publikation automatiskt alla tabeller i databasen, inklusive alla som kommer att skapas i framtiden.
  • pubinsert :Om sant, replikeras INSERT-operationer för tabeller i publikationen.
  • pubuppdatering :Om sant, replikeras UPDATE-operationer för tabeller i publikationen.
  • pubdelete :Om sant, replikeras DELETE-operationer för tabeller i publikationen.
  • pubtruncate :Om sant, replikeras TRUNCATE-operationer för tabeller i publikationen.

Eftersom schemat inte är replikerat måste du ta en säkerhetskopia i PostgreSQL 11 och återställa den i din PostgreSQL 12. Säkerhetskopieringen kommer endast att tas för schemat, eftersom informationen kommer att replikeras i den initiala överföring.

I PostgreSQL 11:

$ pg_dumpall -s > schema.sql

I PostgreSQL 12:

$ psql -d postgres -f schema.sql

När du har ditt schema i PostgreSQL 12 måste du skapa prenumerationen och ersätta värdena för värd, dbname, användare och lösenord med de som motsvarar din miljö.

PostgreSQL 12:

world=# CREATE SUBSCRIPTION sub1 CONNECTION 'host=10.10.10.130 dbname=world user=rep1 password=*****' PUBLICATION pub1;

NOTICE:  created replication slot "sub1" on publisher

CREATE SUBSCRIPTION

Ovanstående startar replikeringsprocessen, som synkroniserar det ursprungliga tabellinnehållet i tabellerna i publikationen och sedan börjar replikera inkrementella ändringar av dessa tabeller.

Användaren som skapar en prenumeration måste vara en superanvändare. Ansökningsprocessen för prenumeration kommer att köras i den lokala databasen med privilegier som en superanvändare.

För att verifiera den skapade prenumerationen kan du använda katalogen pg_stat_subscription. Den här vyn kommer att innehålla en rad per prenumeration för huvudarbetaren (med null PID om arbetaren inte körs), och ytterligare rader för arbetare som hanterar den initiala datakopian av de prenumererade tabellerna.

world=# SELECT * FROM pg_stat_subscription;

-[ RECORD 1 ]---------+------------------------------

subid                 | 16422

subname               | sub1

pid                   | 476

relid                 |

received_lsn          | 0/1771668

last_msg_send_time    | 2020-09-29 17:40:34.711411+00

last_msg_receipt_time | 2020-09-29 17:40:34.711533+00

latest_end_lsn        | 0/1771668

latest_end_time       | 2020-09-29 17:40:34.711411+00

Kolumnbeskrivningar:

  • subid :OID för prenumerationen.
  • undernamn :Namn på prenumerationen.
  • pid :Process-ID för prenumerationsarbetarprocessen.
  • relid :OID för relationen som arbetaren synkroniserar; null för huvudarbetaren.
  • received_lsn :Senaste framskrivningsloggplats mottagen, startvärdet för detta fält är 0.
  • last_msg_send_time :Sändningstid för senaste meddelande mottaget från ursprunglig WAL-avsändare.
  • last_msg_receipt_time :Mottagningstidpunkt för senaste meddelande mottaget från ursprunglig WAL-avsändare.
  • latest_end_lsn :Senaste framskrivningsloggplatsen rapporterades till ursprunglig WAL-avsändare.
  • senaste_sluttid :Tidpunkten för den senaste framskrivningsloggplatsen rapporterad till ursprunglig WAL-avsändare.

För att verifiera statusen för replikering i den primära noden kan du använda pg_stat_replication:

world=# SELECT * FROM pg_stat_replication;

-[ RECORD 1 ]----+------------------------------

pid              | 527

usesysid         | 16428

usename          | rep1

application_name | sub1

client_addr      | 10.10.10.131

client_hostname  |

client_port      | 35570

backend_start    | 2020-09-29 17:40:04.404905+00

backend_xmin     |

state            | streaming

sent_lsn         | 0/1771668

write_lsn        | 0/1771668

flush_lsn        | 0/1771668

replay_lsn       | 0/1771668

write_lag        |

flush_lag        |

replay_lag       |

sync_priority    | 0

sync_state       | async

Kolumnbeskrivningar:

  • pid :Process-ID för en WAL-avsändarprocess.
  • usesysid :OID för användaren som loggat in på denna WAL-avsändarprocess.
  • användarnamn :Namnet på användaren som är inloggad på denna WAL-avsändarprocess.
  • application_name :Namnet på programmet som är anslutet till denna WAL-avsändare.
  • client_addr :IP-adress för klienten som är ansluten till denna WAL-avsändare. Om det här fältet är null indikerar det att klienten är ansluten via en Unix-socket på servermaskinen.
  • client_hostname :Värdnamn för den anslutna klienten, som rapporterats av en omvänd DNS-sökning av client_addr. Det här fältet kommer endast att vara icke-null för IP-anslutningar och endast när log_hostname är aktiverat.
  • client_port :TCP-portnummer som klienten använder för kommunikation med denna WAL-avsändare, eller -1 om en Unix-socket används.
  • backend_start :Tid då denna process startade.
  • backend_xmin :Detta vänteläges xmin-horisont rapporteras av hot_standby_feedback.
  • tillstånd :Aktuellt WAL-avsändarläge. De möjliga värdena är:start, catchup, streaming, backup och stopping.
  • sent_lsn :Senaste framskrivningsloggplatsen skickades på den här anslutningen.
  • write_lsn :Senaste förskrivningsloggplats som skrevs till disken av denna standby-server.
  • flush_lsn :Senast skriv-framåt-loggplats rensades till disken av denna standby-server.
  • replay_lsn :Senaste framskrivningsloggplatsen spelades om i databasen på denna standby-server.
  • write_lag :Tiden förflutit från det att den senaste WAL tömdes lokalt och mottagandet av meddelande om att den här standbyservern har skrivit den (men ännu inte tömt den eller tillämpat den).
  • flush_lag :Tiden förflutit från det att den senaste WAL tömdes lokalt och mottagandet av meddelande om att denna standby-server har skrivit och tömt den (men ännu inte tillämpat den).
  • replay_lag :Tid som förflutit mellan att den senaste WAL tömdes lokalt och mottagandet av meddelande om att denna standby-server har skrivit, tömt och tillämpat den.
  • sync_priority :Prioritet för denna standby-server för att väljas som synkron standby i en prioritetsbaserad synkron replikering.
  • sync_state :Synkront tillstånd för denna standby-server. De möjliga värdena är async, potential, sync, quorum.

För att verifiera när den första överföringen är klar kan du kontrollera PostgreSQL-loggen på abonnenten:

2020-09-29 17:40:04.403 UTC [476] LOG:  logical replication apply worker for subscription "sub1" has started

2020-09-29 17:40:04.411 UTC [477] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has started

2020-09-29 17:40:04.422 UTC [478] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has started

2020-09-29 17:40:04.516 UTC [477] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has finished

2020-09-29 17:40:04.522 UTC [479] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has started

2020-09-29 17:40:04.570 UTC [478] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has finished

2020-09-29 17:40:04.676 UTC [479] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has finished

Eller kontrollera variabeln srsubstate i katalogen pg_subscription_rel. Den här katalogen innehåller tillståndet för varje replikerad relation i varje prenumeration.

world=# SELECT * FROM pg_subscription_rel;

 srsubid | srrelid | srsubstate | srsublsn

---------+---------+------------+-----------

   16422 |   16386 | r          | 0/1771630

   16422 |   16392 | r          | 0/1771630

   16422 |   16399 | r          | 0/1771668

(3 rows)

Kolumnbeskrivningar:

  • srsubid :Referens till prenumeration.
  • srrelid :Referens till relation.
  • srsubstate :Tillståndskod:i =initialisera, d =data kopieras, s =synkroniserad, r =klar (normal replikering).
  • srsublsn :Avsluta LSN för s- och r-tillstånd.

Du kan infoga några testposter i din PostgreSQL 11 och verifiera att du har dem i din PostgreSQL 12:

PostgreSQL 11:

world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5001,'city1','USA','District1',10000);

INSERT 0 1

world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5002,'city2','ITA','District2',20000);

INSERT 0 1

world=# INSERT INTO city (id,name,countrycode,district,population) VALUES (5003,'city3','CHN','District3',30000);

INSERT 0 1

PostgreSQL 12:

world=# SELECT * FROM city WHERE id>5000;

  id  | name  | countrycode | district  | population

------+-------+-------------+-----------+------------

 5001 | city1 | USA         | District1 |      10000

 5002 | city2 | ITA         | District2 |      20000

 5003 | city3 | CHN         | District3 |      30000

(3 rows)

Nu har du allt redo för att peka din ansökan till din PostgreSQL 12.

För detta måste du först och främst bekräfta att du inte har replikeringsfördröjning.

På den primära noden:

world=# SELECT  application_name,  pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) lag FROM pg_stat_replication;

-[ RECORD 1 ]----+-----

application_name | sub1

lag              | 0

Och nu behöver du bara ändra din slutpunkt från din applikation eller belastningsbalanserare (om du har en) till den nya PostgreSQL 12-servern.

Om du har en lastbalanserare som HAProxy kan du konfigurera den med PostgreSQL 11 som aktiv och PostgreSQL 12 som backup, på detta sätt:

Så, om du bara stänger av den gamla primära noden i PostgreSQL 11, backupservern, i detta fall i PostgreSQL 12, börjar ta emot trafiken på ett transparent sätt för användaren/applikationen.

I slutet av migreringen kan du ta bort prenumerationen i din nya primära nod i PostgreSQL 12:

world=# DROP SUBSCRIPTION sub1;

NOTICE:  dropped replication slot "sub1" on publisher

DROP SUBSCRIPTION

Och kontrollera att den har tagits bort korrekt:

world=# SELECT * FROM pg_subscription_rel;

(0 rows)

world=# SELECT * FROM pg_stat_subscription;

(0 rows)

Begränsningar

Tänk på följande begränsningar innan du använder den logiska replikeringen:

  • Databasschemat och DDL-kommandona replikeras inte. Det initiala schemat kan kopieras med pg_dump --schema-only.
  • Sekvensdata replikeras inte. Data i serie- eller identitetskolumner som backas upp av sekvenser kommer att replikeras som en del av tabellen, men själva sekvensen skulle fortfarande visa startvärdet på abonnenten.
  • Replikering av TRUNCATE-kommandon stöds, men viss försiktighet måste iakttas vid trunkering av grupper av tabeller som är anslutna med främmande nycklar. Vid replikering av en trunkeringsåtgärd kommer abonnenten att trunkera samma grupp av tabeller som trunkerades på utgivaren, antingen explicit specificerat eller implicit insamlat via CASCADE, minus tabeller som inte är en del av prenumerationen. Detta kommer att fungera korrekt om alla berörda tabeller är en del av samma prenumeration. Men om några tabeller som ska trunkeras på abonnenten har främmande nyckellänkar till tabeller som inte är en del av samma (eller någon) prenumeration, kommer tillämpningen av trunkeringsåtgärden på abonnenten att misslyckas.
  • Stora objekt replikeras inte. Det finns ingen lösning för det, annat än att lagra data i vanliga tabeller.
  • Replikering är endast möjlig från bastabeller till bastabeller. Det vill säga att tabellerna på publikationen och på prenumerationssidan måste vara normala tabeller, inte vyer, materialiserade vyer, partitionsrottabeller eller främmande tabeller. När det gäller partitioner kan du replikera en partitionshierarki en-till-en, men du kan för närvarande inte replikera till en annan partitionerad inställning.

Slutsats

Att hålla din PostgreSQL-server uppdaterad genom att utföra regelbundna uppgraderingar har varit en nödvändig men svår uppgift fram till PostgreSQL 10-versionen. Lyckligtvis är det nu en annan historia tack vare logisk replikering.

I den här bloggen gjorde vi en kort introduktion till logisk replikering, en PostgreSQL-funktion som introducerades i version 10, och vi har visat dig hur den kan hjälpa dig att uppnå den här uppgraderingen från PostgreSQL 11 till PostgreSQL 12-utmaningen med en noll stilleståndsstrategi.


  1. Hur man importerar/återställer MySql-tabeller med PHP

  2. Spåra automatiska uppdateringar av statistik

  3. 6 problemfrågor som kraftigt saktar ner din databas

  4. Oracle:OALL8 är i ett inkonsekvent tillstånd