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

Brug af PostgreSQL logisk replikering til at vedligeholde en altid opdateret læse-/skrive-TEST-server

I dette blogindlæg vil vi tale om logisk replikering i PostgreSQL:dets use cases, generel information om status for denne teknologi og en speciel use case i særdeleshed om hvordan man opsætter en abonnent (replika) node på den primære server i orden at fungere som databaseserver for testmiljøet, og udfordringerne.

Introduktion

Logisk replikering, officielt introduceret i PostgreSQL 10, er den nyeste replikeringsteknologi, der tilbydes af PostgreSQL-fællesskabet. Logisk replikering er en fortsættelse af arven fra fysisk replikering, som den deler en masse ideer og kode med. Logisk replikering fungerer som fysisk replikering ved at bruge WAL til at registrere logiske ændringer uafhængigt af versionen eller den specifikke arkitektur. For at kunne levere logisk replikering til kernetilbuddet er PostgreSQL-fællesskabet nået langt.

Typer af replikering og historik for PostgreSQL-replikering

Typerne af replikering i databaser kan klassificeres som følger:

  • Fysisk (AKA binær) replikation
    • Operativsystemniveau (vSphere-replikering)
    • Filsystemniveau (DRBD)
    • Databaseniveau (WAL-baseret)
  • Logisk replikering (databaseniveau)
    • Triggerbaseret (DBMirror, Slony)
    • Middleware (pgpool)
    • WAL-baseret (pglogisk, logisk replikering)

Køreplanen, der bringer til dagens WAL-baserede logiske replikering var:

  • 2001:DBMirror (triggerbaseret)
  • 2004:Slony1 (triggerbaseret), pgpool (middleware)
  • 2005:PITR (WAL-baseret) introduceret i PostgreSQL 8.0
  • 2006:Varm standby i PostgreSQL 8.2
  • 2010:Fysisk streamingreplikering, hot standby i PostgreSQL 9.0
  • 2011:Synkron streamingreplikering i PostgreSQL 9.1
  • 2012:Cascading streaming-replikering i PostgreSQL 9.2
  • 2013:Baggrundsarbejdere i PostgreSQL 9.3
  • 2014:Logisk afkodnings-API, replikeringspladser. (grundlaget for logisk replikering) i PostgreSQL 9.4
  • 2015:2ndQuadrant introducerer pglogical, forfaderen eller logisk replikering
  • 2017:Logisk replikering i kerne PostgreSQL 10!

Som vi kan se, har mange teknologier samarbejdet for at gøre logisk replikering til en realitet:WAL-arkivering, varm/varm standby, fysisk WAL-replikering, baggrundsarbejdere, logisk afkodning. Forudsat at læseren er bekendt med de fleste af begreberne fysisk replikering, vil vi tale om de grundlæggende komponenter i logisk replikering.

Grundlæggende begreber for PostgreSQL logisk replikering

Noget terminologi:

  • Publikation: Et sæt ændringer fra et sæt tabeller defineret i en specifik database på en fysisk replikerings primær server. En publikation kan håndtere alle eller nogle af:INSERT, DELETE, UPDATE, TRUNCATE.
  • Udgivernode: Serveren, hvor publikationen ligger.
  • Replika identitet: En måde at identificere rækken på abonnentsiden for OPDATERINGER og SLETNINGER.
  • Abonnement: En forbindelse til en udgivernode og en eller flere publikationer i den. Et abonnement bruger en dedikeret replikeringsplads på udgiveren til replikering. Yderligere replikeringspladser kan bruges til det indledende synkroniseringstrin.
  • Abonnent node: Serveren, hvor abonnementet ligger.

Logisk replikering følger en publicerings-/abonner-model. En eller flere abonnenter kan abonnere på en eller flere publikationer på en udgivernode. Abonnenter kan genudgive for at tillade kaskadereplikering. Logisk replikering af en tabel består af to trin:

  • Tag et øjebliksbillede af tabellen på udgiveren og kopiering til abonnenten
  • Anvendelse af alle ændringer (siden øjebliksbilledet) i samme rækkefølge

Logisk replikering er transaktionsbestemt og garanterer, at rækkefølgen af ​​ændringer, der anvendes på abonnenten, forbliver den samme som på udgiveren. Logisk replikering giver meget mere frihed end fysisk (binær) replikering, og kan derfor bruges på flere måder:

  • Enkelt database- eller tabelspecifik replikering (ingen grund til at replikere hele klyngen)
  • Indstilling af triggere til abonnenten for en bestemt opgave (såsom anonymisering, hvilket er et ret varmt emne efter GDPR trådte i kraft)
  • At lade en abonnent node indsamle data fra mange udgivernoder, hvilket giver mulighed for central analytisk behandling
  • Replikering mellem forskellige versioner/arkitekturer/platforme (nul nedetidsopgraderinger)
  • Brug af abonnentknudepunktet som databaseserver for et test-/udviklingsmiljø. Hvorfor vi ønsker dette, er fordi test mod rigtige data er den mest realistiske form for test.

Forbehold og begrænsninger

Der er visse ting, vi skal have i tankerne, når vi bruger logisk replikering, nogle af dem kan påvirke nogle designbeslutninger, men andre kan føre til kritiske hændelser.

Begrænsninger

  • Kun DML-handlinger understøttes. Ingen DDL. Skemaet skal defineres på forhånd
  • Sekvenser replikeres ikke
  • Store objekter replikeres ikke
  • Kun almindelige basistabeller understøttes (materialiserede visninger, partitionsrodtabeller, fremmede tabeller understøttes ikke)

Forbehold

Det grundlæggende problem, som vi før eller siden bliver nødt til at stå over for, når vi bruger logisk replikering, er konflikter på abonnenten. Abonnenten er en normal læse/skrive-server, der kan fungere som primær i en fysisk replikeringsopsætning, eller endda som udgiver i en kaskadende logisk replikeringsopsætning. Så længe der skrives på de tilmeldte tabeller, kan der være konflikter . En konflikt opstår, når replikerede data overtræder en begrænsning på den tabel, de anvendes på. Normalt vil operationen, der forårsager dette, INSERT, DELETES eller UPDATES, som ikke har nogen effekt på grund af manglende rækker, ikke forårsage en konflikt. Når der opstår en konflikt, stopper replikationen. Den logiske baggrundsarbejder vil blive genstartet i det angivne interval (wal_retrieve_retry_interval), men replikeringen vil mislykkes igen, indtil årsagen til konflikten er løst. Dette er en kritisk tilstand, der skal behandles med det samme. Hvis du ikke gør det, vil replikeringspladsen blive hængende ved sin nuværende position vil udgivernoden begynde at akkumulere WAL'er og uundgåeligt vil udgivernoden løbe tør for diskplads . En konflikt er den mest almindelige årsag til, at replikering kan stoppe, men enhver anden fejlagtig tilstand vil have samme effekt:f.eks. vi tilføjede en ny NOT NULL kolonne på en abonnent tabel, men glemte at definere en standardværdi, eller tilføjede en kolonne på en publiceret tabel, men glemte at definere den på den abonnerede tabel, eller lavede en fejl i dens type, og de to typer er ikke kompatibel. Alle disse fejl vil stoppe replikeringen. Der er to måder at løse en konflikt på:

  1. Løs det faktiske problem
  2. Spring den mislykkede transaktion over ved at kalde pg_replication_origin_advance

Løsning b. som også vist her kan være farligt og vanskeligt, da det dybest set er en trial and error proces, og hvis man vælger den aktuelle LSN på udgiveren, kan han/hun nemt ende med et ødelagt replikeringssystem, da der kan være operationer mellem det problematiske LSN og det nuværende LSN, som vi gerne vil beholde. Så den bedste måde er faktisk at løse problemet på abonnentsiden. For eksempel. hvis der opstår en UNIQUE KEY-overtrædelse, kan vi muligvis opdatere dataene om abonnenten eller blot slette rækken. I et produktionsmiljø skal alt dette være automatiseret eller i det mindste halvautomatiseret.

Opsætning af udgiver- og abonnentknudepunkter

For et generelt overblik over den logiske replikering i praksis, læs venligst denne blog.

De relevante parametre for logisk replikering er:

  • Udgiversiden
    • wal_level>="logisk"
    • max_replication_slots>=#abonnementer + indledende tabelsynkronisering
    • max_wal_senders>=max_replication_slots + other_physical_standbys
  • Abonnentside
    • max_replication_slots>=#abonnementer
    • max_logical_replication_workers>=#abonnementer + indledende tabelsynkronisering
    • max_worker_processes>=max_logical_replication_workers + 1 + max_parallel_workers

Vi vil fokusere på de særlige overvejelser, der udspringer af vores særlige formål, som vi har brug for logisk replikering for at opnå:opret en testdatabaseklynge til brug for testafdelingen . Publikationen kan defineres enten for alle tabeller eller tabel for tabel. Jeg foreslår en tabel for tabel-tilgang, da den giver os maksimal fleksibilitet. De generelle trin kan opsummeres som følger:

  • Udfør en ny initdb på abonnentnoden
  • Dump skemaet for udgiverklyngen og kopier til abonnentknudepunktet
  • Opret skemaet på abonnenten
  • Beslut dig for, hvilke borde du skal bruge, og hvilke du ikke har brug for.

Med hensyn til ovenstående punkttegn er der to grunde til, hvorfor du muligvis ikke har brug for en tabel, der skal replikeres eller konfigureres til replikering:

  • Det er et dummybord uden betydning (og måske skulle du også droppe det fra produktionen)
  • er en tabel lokalt i produktionsmiljøet, hvilket betyder, at det giver god mening, at den samme tabel i testmiljøet (abonnent) har sine egne data

Alle tabeller, der deltager i den logiske replikering, skal have en REPLICA IDENTITET. Dette er som standard den PRIMÆRE NØGLE, og hvis den ikke er tilgængelig, kan en UNIK nøgle defineres. Næste trin for at finde status for tabellerne med hensyn til REPLICA IDENTITET.

  • Find tabellerne uden nogen åbenlys kandidat til REPLICA IDENTITY
    select table_schema||'.'||table_name from information_schema.tables where table_type='BASE TABLE' AND table_schema||'.'||table_name NOT IN (select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type in ('PRIMARY KEY','UNIQUE')) AND table_schema NOT IN ('information_schema','pg_catalog') ;
  • Find tabellerne uden PRIMÆR NØGLE, men med et UNIKT INDEX
    select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type = 'UNIQUE' EXCEPT select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type = 'PRIMARY KEY';
  • Gennem de ovenstående lister og beslut, hvad du skal gøre med hver tabel
  • Opret publikationen med de tabeller, for hvilke der findes en PK
    select 'CREATE PUBLICATION data_for_testdb_pub FOR TABLE ONLY ' || string_agg(qry.tblname,', ONLY ') FROM (select table_schema||'.'||quote_ident(table_name) as tblname from information_schema.tables where table_type='BASE TABLE' AND table_schema||'.'||table_name IN (select table_schema||'.'||table_name from information_schema.table_constraints WHERE constraint_type in ('PRIMARY KEY')) AND table_schema NOT IN( 'information_schema','pg_catalog')  ORDER BY 1) as qry;
    \gexec
  • Opret derefter abonnementet på abonnentnoden
    create subscription data_for_testdb_pub CONNECTION 'dbname=yourdb host=yourdbhost user=repmgr' PUBLICATION data_for_testdb_pub ;
    Ovenstående kopierer også dataene.
  • Tilføj tabeller, som du ønsker, som har et UNIKT indeks
    Kør både i udgiver- og abonnentknudepunkter, f.eks.:
    ALTER TABLE someschema.yourtable REPLICA IDENTITY USING INDEX yourindex_ukey;
    På udgiveren:
    ALTER PUBLICATION data_for_testdb_pub ADD TABLE ONLY someschema.yourtable;
    På abonnenten:
    ALTER SUBSCRIPTION data_for_testdb_pub REFRESH PUBLICATION WITH ( COPY_DATA );
  • På dette tidspunkt (synkronisering) bør du altid have øje med PostgreSQL-loggen på abonnentnoden. Du ønsker ikke nogen fejl eller noget (timeout), som forbyder fortsættelsen af ​​logisk replikering. LØS ENHVER FEJL STRAKS , ellers vil udgiveren blive ved med at akkumulere WAL-filer i pg_wal og til sidst løbe tør for plads. Så du er nødt til at forholde dig til
    • Alle FEJL eller enhver meddelelse vedrørende den logiske arbejder, som resulterer i at afslutte
    • Tag også dig af
      • wal_receiver_timeout
      • wal_sender_timeout

Efter at have løst alle problemer bør du have din abonnentnode kørende. Så det næste spørgsmål er, hvordan man bruger dette som en testdatabaseserver. Du bliver nødt til at håndtere disse problemer/problemer:

  1. Anonymisering
  2. Primære nøgler og unikke nøgler, som er baseret på sekvensovertrædelser
  3. Et generelt sæt af god praksis
  4. Overvågning

Anonymisering

Vedrørende anonymisering af persondata, som håndhæves af GDPR i EU, bør du skrive nogle ALTID triggere, der udtømmer alle felter vedrørende adresser, bankkonti, civilstand, telefonnumre, e-mails osv. Du bør rådføre dig med din sikkerhedsansvarlige i din virksomhed vedr. hvad man skal beholde, og hvad man skal slette. Udløserne skal defineres som ALTID, da den logiske arbejder kører sætningerne som REPLICA.

Primære nøgler med sekvenser

Med hensyn til sekvenser vil der helt klart være et problem med disse nøgler, medmindre de løses, før en test startes. Overvej dette tilfælde:

  • Fredag ​​eftermiddag laver du nogle test på abonnentdatabasen ved at indsætte en ny række i en tabel. Dette vil have som ID den næste værdi, der genereres af sekvensen.
  • Du tager hjem i weekenden.
  • En eller anden produktionsbruger indtaster en række i den samme tabel i udgiverdatabasen.
  • Rækken vil blive replikeret baseret på REPLICA IDENTITY til abonnentknudepunktet, men vil mislykkes på grund af PK overtrædelse FEJL. Den logiske baggrundsarbejder afslutter og prøver igen. Men vil blive ved med at fejle, så længe problemet fortsætter.
  • Replikationen sætter sig fast. Replikationspladsen vil begynde at akkumulere WAL'er.
  • Udgiveren løber tør for diskplads.
  • I weekenden får du en e-mail om, at din primære node er gået i panik!

Så for at løse sekvensproblemet kan du tage følgende fremgangsmåde:

select 'SELECT setval(''' || seqrelid::regclass||''','||CASE WHEN seqincrement <0 THEN -214748364 ELSE 214748364 END||');' from pg_sequence where seqtypid=20;
\gexec

Hvad ovenstående gør, er at indstille sekvenser til en tilstrækkelig stor værdi, så de aldrig overlapper hinanden for et ret stort vindue i fremtiden, hvilket giver dig mulighed for at have en problemfri testserver.

Et sæt god praksis

Du bør virkelig fortælle dine programmører at gøre deres tests ikke-vedholdende. Så enhver test, efter den er fuldført, bør efterlade databasen i samme tilstand, som den var før testen. Med sekvens-baserede ID'er indsættelser er dette ikke et problem, vi så tidligere en løsning. Men med ikke-sekvens (f.eks. sammensatte) UNIKKE nøgler kan det være et problem. Så det er bedst at slette disse testdata, før en produktionsrække med samme værdi rammer den tilmeldte tabel.

Her bør vi også tilføje håndtering af skemaændringer. Alle skemaændringer skal også udføres på abonnenten for ikke at bryde replikeret DML-trafik.

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

Overvågning

Du bør virkelig investere i en god overvågningsløsning. Du bør overvåge for ...

Hos abonnenten:

  • ALLE meddelelser i abonnentens log, der er relevante for logisk arbejderafslutning. Installation af et værktøj som tail_n_mail kan virkelig hjælpe med dette. En konfiguration, der vides at virke:
    INCLUDE: ERROR:  .*publisher.*
    INCLUDE: ERROR:  .*exited with exit.*
    INCLUDE: LOG:  .*exited with exit.*
    INCLUDE: FATAL:  
    INCLUDE: PANIC:
    Når vi får en advarsel fra tail_n_mail, bør vi straks løse problemet.
  • pg_stat_subscription. Pid bør ikke være nul. Også forsinkelsen skal være lille.

Hos forlaget:

  • pg_stat_replikering. Denne skal have lige så mange rækker, som de formodes at være:Én for hver tilsluttet streaming-replikeringsstandby (abonnentnoder og andre fysiske standbyer inkluderet).
  • pg_replication_slots for abonnentpladsen. Dette skal være aktivt.

Generelt tager det lidt tid, før du har din ideelle testdatabaseserver kørende uden problemer, men når du har løst dem alle, vil dine programmører takke dig for at have den!


  1. Sæt en dato i SQL-serveren

  2. Sådan fungerer Date()-funktionen i SQLite

  3. Skift og nulstil MySQL root-adgangskode

  4. lastInsertId virker ikke i Postgresql