sql >> Database teknologi >  >> RDS >> PostgreSQL

Sådan opgraderes PostgreSQL10 til PostgreSQL11 med nul nedetid

Historisk set har den sværeste opgave, når man arbejder med PostgreSQL, været at håndtere opgraderingerne. Den mest intuitive opgraderingsmåde, du kan tænke på, er at generere en replika i en ny version og udføre en failover af applikationen ind i den. Med PostgreSQL var dette simpelthen ikke muligt på en indbygget måde. For at opnå opgraderinger var du nødt til at tænke på andre måder at opgradere på, såsom at bruge pg_upgrade, dumping og gendannelse eller bruge nogle tredjepartsværktøjer som Slony eller Bucardo, som alle har deres egne forbehold.

Hvorfor var dette? På grund af den måde PostgreSQL implementerer replikering på.

PostgreSQL indbygget streaming-replikering er, hvad der kaldes fysisk:det vil replikere ændringerne på et byte-for-byte-niveau, hvilket skaber en identisk kopi af databasen på en anden server. Denne metode har mange begrænsninger, når du tænker på en opgradering, da du simpelthen ikke kan oprette en replika i en anden serverversion eller endda i en anden arkitektur.

Så det er her, PostgreSQL 10 bliver en game changer. Med disse nye versioner 10 og 11 implementerer PostgreSQL indbygget logisk replikering, som du i modsætning til fysisk replikering kan replikere mellem forskellige større versioner af PostgreSQL. Dette åbner selvfølgelig en ny dør for opgraderingsstrategier.

Lad os i denne blog se, hvordan vi kan opgradere vores PostgreSQL 10 til PostgreSQL 11 med nul nedetid ved hjælp af logisk replikering. Først og fremmest, lad os gennemgå en introduktion til logisk replikering.

Hvad er logisk replikering?

Logisk replikering er en metode til at replikere dataobjekter og deres ændringer baseret på deres replikeringsidentitet (normalt en primær nøgle). Den er baseret på en udgivelses- og abonnenttilstand, hvor en eller flere abonnenter abonnerer på en eller flere publikationer på en udgivernode.

En publikation er et sæt ændringer genereret fra en tabel eller en gruppe af tabeller (også kaldet replikeringssæt). Noden, hvor en publikation er defineret, omtales som udgiver. Et abonnement er downstream-siden af ​​logisk replikering. Noden, hvor et abonnement er defineret, omtales som abonnenten, og det definerer forbindelsen til en anden database og et sæt publikationer (en eller flere), som den ønsker at abonnere på. Abonnenter henter data fra de publikationer, de abonnerer på.

Logisk replikering er bygget med en arkitektur svarende til fysisk streaming replikering. Det er implementeret af "walsender" og "anvend" processer. Walsender-processen starter logisk afkodning af WAL og indlæser standard logisk afkodningsplugin. Pluginnet transformerer de læste ændringer fra WAL til den logiske replikeringsprotokol og filtrerer dataene i henhold til publikationsspecifikationen. Dataene overføres derefter løbende ved hjælp af streaming-replikeringsprotokollen til appliceringsarbejderen, som kortlægger dataene til lokale tabeller og anvender de individuelle ændringer, efterhånden som de modtages, i en korrekt transaktionsrækkefølge.

Logisk replikeringsdiagram

Logisk replikering starter med at tage et øjebliksbillede af dataene i udgiverdatabasen og kopiere dem til abonnenten. De indledende data i de eksisterende tilmeldte tabeller tages snapshots og kopieres i en parallel instans af en særlig form for ansøgningsproces. Denne proces vil oprette sin egen midlertidige replikeringsplads og kopiere de eksisterende data. Når de eksisterende data er kopieret, går arbejderen i synkroniseringstilstand, som sikrer, at tabellen bringes op til en synkroniseret tilstand med hovedanvendelsesprocessen ved at streame ændringer, der skete under den indledende datakopiering, ved hjælp af standard logisk replikering. Når synkroniseringen er udført, bliver kontrollen over replikeringen af ​​tabellen givet tilbage til hovedanvendelsesprocessen, hvor replikeringen fortsætter som normalt. Ændringerne på udgiveren sendes til abonnenten, efterhånden som de sker i realtid.

Du kan finde mere om logisk replikering i følgende blogs:

  • En oversigt over logisk replikering i PostgreSQL
  • PostgreSQL-streamingreplikering vs logisk replikering

Sådan opgraderer du PostgreSQL 10 til PostgreSQL 11 ved hjælp af logisk replikering

Så nu hvor vi ved, hvad denne nye funktion handler om, kan vi tænke over, hvordan vi kan bruge den til at løse opgraderingsproblemet.

Vi skal konfigurere logisk replikering mellem to forskellige større versioner af PostgreSQL (10 og 11), og selvfølgelig, når du har fået dette til at virke, er det kun et spørgsmål om at udføre en applikations-failover i databasen med den nyere version.

Vi skal udføre følgende trin for at få logisk replikering til at fungere:

  • Konfigurer udgivernoden
  • Konfigurer abonnentnoden
  • Opret abonnentbrugeren
  • Opret en publikation
  • Opret tabelstrukturen i abonnenten
  • Opret abonnementet
  • Tjek replikeringsstatussen

Så lad os starte.

På udgiversiden skal vi konfigurere følgende parametre i postgresql.conf-filen:

  • lytteadresser:Hvilke(n) IP-adresse(r) der skal lyttes på. Vi bruger '*' for alle.
  • wal_level:Bestemmer, hvor meget information der skrives til WAL. Vi vil indstille det til logisk.
  • max_replication_slots:Angiver det maksimale antal replikeringspladser, som serveren kan understøtte. Den skal som minimum indstilles til det antal abonnementer, der forventes at forbinde, plus en vis reserve til bordsynkronisering.
  • max_wal_senders:Angiver det maksimale antal samtidige forbindelser fra standby-servere eller streaming-base backup-klienter. Den skal være indstillet til mindst det samme som max_replication_slots plus antallet af fysiske replikaer, der er forbundet på samme tid.

Husk, at nogle af disse parametre krævede en genstart af PostgreSQL-tjenesten for at kunne anvendes.

Filen pg_hba.conf skal også justeres for at tillade replikering. Vi skal tillade replikeringsbrugeren at oprette forbindelse til databasen.

Så baseret på dette, lad os konfigurere vores udgiver (i dette tilfælde vores PostgreSQL 10-server) som følger:

  • 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     rep     192.168.100.144/32     md5

Vi skal ændre brugeren (i vores eksempel rep), som vil blive brugt til replikering, og IP-adressen 192.168.100.144/32 for den IP, der svarer til vores PostgreSQL 11.

På abonnentsiden kræver det også, at max_replication_slots er indstillet. I dette tilfælde skal den indstilles til mindst antallet af abonnementer, der vil blive tilføjet til abonnenten.

De andre parametre, der også skal indstilles her, er:

  • max_logical_replication_workers:Angiver det maksimale antal logiske replikeringsarbejdere. Dette inkluderer både anvende arbejdere og tabelsynkroniseringsarbejdere. Logiske replikeringsarbejdere tages fra puljen defineret af max_worker_processes. Den skal som minimum indstilles til antallet af abonnementer, igen plus en vis reserve til bordsynkronisering.
  • max_worker_processes:Indstiller det maksimale antal baggrundsprocesser, som systemet kan understøtte. Den skal muligvis justeres for at imødekomme replikeringsarbejdere, mindst max_logical_replication_workers + 1. Denne parameter kræver en PostgreSQL-genstart.

Så vi skal konfigurere vores abonnent (i dette tilfælde vores PostgreSQL 11-server) som følger:

  • postgresql.conf:
    listen_addresses = '*'
    max_replication_slots = 4
    max_logical_replication_workers = 4
    max_worker_processes = 8

Da denne PostgreSQL 11 snart bliver vores nye master, bør vi overveje at tilføje parametrene wal_level og archive_mode i dette trin for at undgå en ny genstart af tjenesten senere.

wal_level = logical
archive_mode = on

Disse parametre vil være nyttige, hvis vi ønsker at tilføje en ny replikeringsslave eller til at bruge PITR-sikkerhedskopier.

I udgiveren skal vi oprette den bruger, som vores abonnent vil forbinde med:

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

Den rolle, der bruges til replikeringsforbindelsen, skal have attributten REPLIKATION. Adgang til rollen skal konfigureres i pg_hba.conf, og den skal have LOGIN-attributten.

For at kunne kopiere de oprindelige data skal den rolle, der bruges til replikeringsforbindelsen, have SELECT-privilegiet på en offentliggjort tabel.

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

Vi opretter pub1-publikation i udgivernoden for alle tabellerne:

world=# CREATE PUBLICATION pub1 FOR ALL TABLES;
CREATE PUBLICATION

Brugeren, der vil oprette en publikation, skal have CREATE-privilegiet i databasen, men for at oprette en publikation, der udgiver alle tabeller automatisk, skal brugeren være en superbruger.

For at bekræfte den oprettede publikation vil vi bruge pg_publication-kataloget. Dette katalog indeholder information om alle publikationer, der er oprettet i databasen.

world=# SELECT * FROM pg_publication;
-[ RECORD 1 ]+------
pubname      | pub1
pubowner     | 16384
puballtables | t
pubinsert    | t
pubupdate    | t
pubdelete    | t

Kolonnebeskrivelser:

  • pubnavn:Navn på publikationen.
  • Pubejer:Ejer af publikationen.
  • publikationstabeller:Hvis sandt, inkluderer denne publikation automatisk alle tabeller i databasen, inklusive dem, der vil blive oprettet i fremtiden.
  • pubinsert:Hvis sandt, replikeres INSERT-operationer for tabeller i publikationen.
  • pubupdate:Hvis sandt, replikeres UPDATE-handlinger for tabeller i publikationen.
  • pubdelete:Hvis sandt, replikeres DELETE-handlinger for tabeller i publikationen.

Da skemaet ikke er replikeret, skal vi tage en sikkerhedskopi i PostgreSQL 10 og gendanne den i vores PostgreSQL 11. Sikkerhedskopien vil kun blive taget for skemaet, da informationen vil blive replikeret i den indledende overførsel.

I PostgreSQL 10:

$ pg_dumpall -s > schema.sql

I PostgreSQL 11:

$ psql -d postgres -f schema.sql

Når vi har vores skema i PostgreSQL 11, opretter vi abonnementet og erstatter værdierne for vært, dbname, bruger og adgangskode med dem, der svarer til vores miljø.

PostgreSQL 11:

world=# CREATE SUBSCRIPTION sub1 CONNECTION 'host=192.168.100.143 dbname=world user=rep password=*****' PUBLICATION pub1;
NOTICE:  created replication slot "sub1" on publisher
CREATE SUBSCRIPTION

Ovenstående starter replikeringsprocessen, som synkroniserer det indledende tabelindhold i tabellerne i publikationen og derefter begynder at replikere trinvise ændringer til disse tabeller.

Brugeren, der opretter et abonnement, skal være en superbruger. Abonnementsanvendelsesprocessen vil køre i den lokale database med privilegier som en superbruger.

For at bekræfte det oprettede abonnement kan vi bruge derefter pg_stat_subscription katalog. Denne visning vil indeholde én række pr. abonnement for hovedarbejderen (med null PID, hvis arbejderen ikke kører), og yderligere rækker for arbejdere, der håndterer den indledende datakopi af de tilmeldte tabeller.

world=# SELECT * FROM pg_stat_subscription;
-[ RECORD 1 ]---------+------------------------------
subid                 | 16428
subname               | sub1
pid                   | 1111
relid                 |
received_lsn          | 0/172AF90
last_msg_send_time    | 2018-12-05 22:11:45.195963+00
last_msg_receipt_time | 2018-12-05 22:11:45.196065+00
latest_end_lsn        | 0/172AF90
latest_end_time       | 2018-12-05 22:11:45.195963+00

Kolonnebeskrivelser:

  • subid:OID for abonnementet.
  • undernavn:Navn på abonnementet.
  • pid:Proces-id for abonnementsarbejderprocessen.
  • relid:OID for den relation, som arbejderen synkroniserer; null for hovedansøgeren.
  • received_lsn:Sidste fremskrivningslogplacering modtaget, startværdien af ​​dette felt er 0.
  • last_msg_send_time:Sendetidspunkt for sidste besked modtaget fra oprindelig WAL-afsender.
  • last_msg_receipt_time:Modtagelsestidspunkt for sidste besked modtaget fra oprindelig WAL-afsender.
  • latest_end_lsn:Sidste fremskrivningslogplacering rapporteret til oprindelig WAL-afsender.
  • latest_end_time:Tidspunktet for sidste fremskrivningslogplacering rapporteret til den oprindelige WAL-afsender.

For at verificere status for replikering i masteren kan vi bruge pg_stat_replication:

world=# SELECT * FROM pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid              | 1178
usesysid         | 16427
usename          | rep
application_name | sub1
client_addr      | 192.168.100.144
client_hostname  |
client_port      | 58270
backend_start    | 2018-12-05 22:11:45.097539+00
backend_xmin     |
state            | streaming
sent_lsn         | 0/172AF90
write_lsn        | 0/172AF90
flush_lsn        | 0/172AF90
replay_lsn       | 0/172AF90
write_lag        |
flush_lag        |
replay_lag       |
sync_priority    | 0
sync_state       | async

Kolonnebeskrivelser:

  • pid:Proces-id for en WAL-afsenderproces.
  • usesysid:OID for den bruger, der er logget på denne WAL-afsenderproces.
  • brugsnavn:Navnet på den bruger, der er logget på denne WAL-afsenderproces.
  • application_name:Navnet på den applikation, der er forbundet til denne WAL-afsender.
  • client_addr:IP-adressen på den klient, der er forbundet til denne WAL-afsender. Hvis dette felt er null, angiver det, at klienten er forbundet via en Unix-socket på servermaskinen.
  • client_hostname:Værtsnavn på den tilsluttede klient, som rapporteret af et omvendt DNS-opslag af client_addr. Dette felt vil kun være ikke-nul for IP-forbindelser, og kun når log_hostname er aktiveret.
  • client_port:TCP-portnummer, som klienten bruger til kommunikation med denne WAL-afsender, eller -1, hvis der bruges en Unix-socket.
  • backend_start:Tidspunktet, hvor denne proces blev startet.
  • backend_xmin:Denne standbys xmin-horisont rapporteret af hot_standby_feedback.
  • tilstand:Aktuel WAL-afsendertilstand. De mulige værdier er:start, catchup, streaming, backup og stop.
  • sent_lsn:Sidste skrive-ahead-logplacering sendt på denne forbindelse.
  • write_lsn:Sidste fremskrivningslogplacering skrevet til disken af ​​denne standby-server.
  • flush_lsn:Sidste skrive-ahead-logplacering blev tømt til disken af ​​denne standby-server.
  • replay_lsn:Sidste skrive-ahead-logplacering afspillet i databasen på denne standby-server.
  • write_lag:Tiden forløbet mellem tømning af seneste WAL lokalt og modtagelse af meddelelse om, at denne standby-server har skrevet den (men endnu ikke tømt den eller anvendt den).
  • flush_lag:Tiden forløbet mellem fjernelse af seneste WAL lokalt og modtagelse af meddelelse om, at denne standby-server har skrevet og tømt den (men endnu ikke anvendt den).
  • replay_lag:Tiden forløbet mellem fjernelse af seneste WAL lokalt og modtagelse af besked om, at denne standby-server har skrevet, skyllet og anvendt den.
  • sync_priority:Prioritet for denne standby-server for at blive valgt som synkron standby i en prioritetsbaseret synkron replikering.
  • sync_state:Synkron tilstand for denne standby-server. De mulige værdier er async, potential, sync, quorum.

For at bekræfte, hvornår den indledende overførsel er afsluttet, kan vi se PostgreSQL-loggen på abonnenten:

2018-12-05 22:11:45.096 UTC [1111] LOG:  logical replication apply worker for subscription "sub1" has started
2018-12-05 22:11:45.103 UTC [1112] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has started
2018-12-05 22:11:45.114 UTC [1113] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has started
2018-12-05 22:11:45.156 UTC [1112] LOG:  logical replication table synchronization worker for subscription "sub1", table "city" has finished
2018-12-05 22:11:45.162 UTC [1114] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has started
2018-12-05 22:11:45.168 UTC [1113] LOG:  logical replication table synchronization worker for subscription "sub1", table "country" has finished
2018-12-05 22:11:45.206 UTC [1114] LOG:  logical replication table synchronization worker for subscription "sub1", table "countrylanguage" has finished

Eller kontroller srsubstate-variablen på pg_subscription_rel-kataloget. Dette katalog indeholder tilstanden for hver replikeret relation i hvert abonnement.

world=# SELECT * FROM pg_subscription_rel;
-[ RECORD 1 ]---------
srsubid    | 16428
srrelid    | 16387
srsubstate | r
srsublsn   | 0/172AF20
-[ RECORD 2 ]---------
srsubid    | 16428
srrelid    | 16393
srsubstate | r
srsublsn   | 0/172AF58
-[ RECORD 3 ]---------
srsubid    | 16428
srrelid    | 16400
srsubstate | r
srsublsn   | 0/172AF90

Kolonnebeskrivelser:

  • srsubid:Reference til abonnement.
  • srrelid:Reference til relation.
  • srsubstate:Tilstandskode:i =initialisere, d =data bliver kopieret, s =synkroniseret, r =klar (normal replikering).
  • srsublsn:Afslut LSN for s- og r-tilstande.

Vi kan indsætte nogle testposter i vores PostgreSQL 10 og validere, at vi har dem i vores PostgreSQL 11:

PostgreSQL 10:

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 11:

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)

På dette tidspunkt har vi alt klar til at pege vores applikation til vores PostgreSQL 11.

Til dette skal vi først og fremmest bekræfte, at vi ikke har replikeringsforsinkelse.

På masteren:

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

Og nu skal vi kun ændre vores endepunkt fra vores applikation eller belastningsbalancer (hvis vi har en) til den nye PostgreSQL 11-server.

Hvis vi har en load balancer som HAProxy, kan vi konfigurere den ved at bruge PostgreSQL 10 som aktiv og PostgreSQL 11 som backup, på denne måde:

HAProxy-statusvisning

Så hvis du bare lukker masteren ned i PostgreSQL 10, begynder backupserveren, i dette tilfælde i PostgreSQL 11, at modtage trafikken på en gennemsigtig måde for brugeren/applikationen.

Ved afslutningen af ​​migreringen kan vi slette abonnementet i vores nye master i PostgreSQL 11:

world=# DROP SUBSCRIPTION sub1;
NOTICE:  dropped replication slot "sub1" on publisher
DROP SUBSCRIPTION

Og bekræft, at den er fjernet korrekt:

world=# SELECT * FROM pg_subscription_rel;
(0 rows)
world=# SELECT * FROM pg_stat_subscription;
(0 rows)
Download Whitepaper Today PostgreSQL Management &Automation med ClusterControlFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere PostgreSQLDownload Whitepaper

Begrænsninger

Før du bruger den logiske replikering, skal du huske følgende begrænsninger:

  • Databaseskemaet og DDL-kommandoer replikeres ikke. Det indledende skema kan kopieres ved hjælp af pg_dump --schema-only.
  • Sekvensdata er ikke replikeret. Dataene i serie- eller identitetskolonner understøttet af sekvenser vil blive replikeret som en del af tabellen, men selve sekvensen vil stadig vise startværdien på abonnenten.
  • Replikering af TRUNCATE-kommandoer er understøttet, men der skal udvises en vis forsigtighed ved trunkering af grupper af tabeller forbundet med fremmednøgler. Når du replikerer en trunkeringshandling, vil abonnenten trunkere den samme gruppe af tabeller, som blev afkortet på udgiveren, enten eksplicit specificeret eller implicit indsamlet via CASCADE, minus tabeller, der ikke er en del af abonnementet. Dette vil fungere korrekt, hvis alle berørte tabeller er en del af det samme abonnement. Men hvis nogle tabeller, der skal afkortes på abonnenten, har fremmednøglelinks til tabeller, der ikke er en del af det samme (eller noget) abonnement, vil anvendelsen af ​​trunkeringshandlingen på abonnenten mislykkes.
  • Store objekter replikeres ikke. Der er ingen løsning på det, udover at gemme data i normale tabeller.
  • Replikering er kun mulig fra basistabeller til basistabeller. Det vil sige, at tabellerne på publikationen og på abonnementssiden skal være normale tabeller, ikke visninger, materialiserede visninger, partitionsrodtabeller eller fremmede tabeller. I tilfælde af partitioner kan du replikere et partitionshierarki en-til-en, men du kan i øjeblikket ikke replikere til en anderledes partitioneret opsætning.

Konklusion

At holde din PostgreSQL-server opdateret ved at udføre regelmæssige opgraderinger har været en nødvendig, men vanskelig opgave indtil PostgreSQL 10-versionen.

I denne blog har vi lavet en kort introduktion til logisk replikering, en PostgreSQL-funktion, der blev introduceret indbygget i version 10, og vi har vist dig, hvordan den kan hjælpe dig med at klare denne udfordring med en strategi uden nedetid.


  1. SQL:Hvad er bedre en bit eller et tegn(1)

  2. Hvad er MySQL? – En introduktion til databasestyringssystemer

  3. Sådan gemmer du sqlite-database direkte på sdcard

  4. Bestilling af resultater af ivrigt indlæste indlejrede modeller i Node Sequelize