sql >> Database >  >> RDS >> PostgreSQL

Logische PostgreSQL-replicatie gebruiken om een ​​altijd up-to-date lees/schrijf TEST-server te onderhouden

In dit blogbericht zullen we praten over logische replicatie in PostgreSQL:de use-cases, algemene informatie over de status van deze technologie en een speciale use-case in het bijzonder over het opzetten van een abonnee (replica) node van de primaire server om om te functioneren als de databaseserver voor de testomgeving en de uitdagingen die zijn aangegaan.

Inleiding

Logische replicatie, officieel geïntroduceerd in PostgreSQL 10, is de nieuwste replicatietechnologie die wordt aangeboden door de PostgreSQL-gemeenschap. Logische replicatie is een voortzetting van de erfenis van fysieke replicatie waarmee het veel ideeën en code deelt. Logische replicatie werkt als fysieke replicatie waarbij de WAL wordt gebruikt om logische wijzigingen vast te leggen, onafhankelijk van de versie of specifieke architectuur. Om logische replicatie naar het kernaanbod te kunnen bieden, heeft de PostgreSQL-gemeenschap een lange weg afgelegd.

Typen replicatie en geschiedenis van PostgreSQL-replicatie

De soorten replicatie in databases kunnen als volgt worden ingedeeld:

  • Fysieke (AKA binaire) replicatie
    • Op besturingssysteemniveau (vSphere-replicatie)
    • Bestandssysteemniveau (DRBD)
    • Databaseniveau (gebaseerd op WAL)
  • Logische replicatie (databaseniveau)
    • Triggergebaseerd (DBMirror, Slony)
    • Middleware (pgpool)
    • WAL-gebaseerd (pglogisch, logische replicatie)

De routekaart die leidt tot de op WAL gebaseerde logische replicatie van vandaag was:

  • 2001:DBMirror (gebaseerd op triggers)
  • 2004:Slony1 (gebaseerd op triggers), pgpool (middleware)
  • 2005:PITR (op WAL gebaseerd) geïntroduceerd in PostgreSQL 8.0
  • 2006:Warm stand-by in PostgreSQL 8.2
  • 2010:fysieke streaming-replicatie, hot standby in PostgreSQL 9.0
  • 2011:synchrone streaming-replicatie in PostgreSQL 9.1
  • 2012:trapsgewijze streaming-replicatie in PostgreSQL 9.2
  • 2013:Achtergrondwerkers in PostgreSQL 9.3
  • 2014:Logische decoderings-API, replicatieslots. (De basis voor logische replicatie) in PostgreSQL 9.4
  • 2015:2ndQuadrant introduceert pglogical, de voorouder of logische replicatie
  • 2017:logische replicatie in core PostgreSQL 10!

Zoals we kunnen zien, hebben veel technologieën samengewerkt om logische replicatie mogelijk te maken:WAL-archivering, warme/warme standbys, fysieke WAL-replicatie, achtergrondwerkers, logische decodering. Ervan uitgaande dat de lezer bekend is met de meeste noties van fysieke replicatie, zullen we het hebben over de basiscomponenten van logische replicatie.

Basisconcepten voor logische replicatie van PostgreSQL

Enige terminologie:

  • Publicatie: Een set wijzigingen van een set tabellen die is gedefinieerd in een specifieke database op een primaire fysieke replicatieserver. Een publicatie kan alle of enkele van de volgende zaken aan:INSERT, DELETE, UPDATE, TRUNCATE.
  • Uitgeversknooppunt: De server waar de publicatie zich bevindt.
  • Replica identiteit: Een manier om de rij aan de abonneezijde te identificeren voor UPDATE's en DELETE's.
  • Abonnement: Een verbinding met een uitgeversknooppunt en een of meer publicaties daarin. Een abonnement gebruikt een speciale replicatiesleuf op de uitgever voor replicatie. Extra replicatieslots kunnen worden gebruikt voor de eerste synchronisatiestap.
  • Abonneeknooppunt: De server waar het abonnement zich bevindt.

Logische replicatie volgt een publish/subscribe-model. Een of meer abonnees kunnen zich abonneren op een of meer publicaties op een uitgeversknooppunt. Abonnees kunnen opnieuw publiceren om trapsgewijze replicatie mogelijk te maken. Logische replicatie van een tabel bestaat uit twee fasen:

  • Een momentopname maken van de tabel op de uitgever en deze kopiëren naar de abonnee
  • Alle wijzigingen (sinds de momentopname) in dezelfde volgorde toepassen

Logische replicatie is transactioneel en garandeert dat de volgorde van wijzigingen die worden toegepast op de abonnee hetzelfde blijft als op de uitgever. Logische replicatie geeft veel meer vrijheid dan fysieke (binaire) replicatie en kan daarom op meer manieren worden gebruikt:

  • Enkele database- of tabelspecifieke replicatie (niet nodig om het hele cluster te repliceren)
  • Triggers instellen voor de abonnee voor een specifieke taak (zoals anonimiseren, wat een behoorlijk hot topic is nadat de AVG van kracht werd)
  • Als een abonneeknooppunt gegevens verzamelt van veel uitgeversknooppunten, is centrale analytische verwerking mogelijk
  • Replicatie tussen verschillende versies/architecturen/platforms (upgrades zonder downtime)
  • Het abonneeknooppunt gebruiken als databaseserver voor een test-/ontwikkelomgeving. Waarom we dit willen, is omdat testen met echte gegevens de meest realistische soort tests is.

Voorbehouden en beperkingen

Er zijn bepaalde dingen die we in gedachten moeten houden bij het gebruik van logische replicatie, sommige kunnen sommige ontwerpbeslissingen beïnvloeden, maar andere kunnen leiden tot kritieke incidenten.

Beperkingen

  • Alleen DML-bewerkingen worden ondersteund. Geen DDL. Het schema moet vooraf worden gedefinieerd
  • Sequenties worden niet gerepliceerd
  • Grote objecten worden niet gerepliceerd
  • Alleen gewone basistabellen worden ondersteund (gematerialiseerde weergaven, partitie-roottabellen, externe tabellen worden niet ondersteund)

Voorbehoud

Het basisprobleem waarmee we vroeg of laat te maken krijgen bij het gebruik van logische replicatie, zijn conflicten bij de abonnee. De abonnee is een normale lees-/schrijfserver die als primair kan fungeren in een fysieke replicatie-opstelling, of zelfs als uitgever in een trapsgewijze logische replicatie-opstelling. Zolang schrijfacties op de geabonneerde tabellen worden uitgevoerd, kunnen er conflicten zijn . Er ontstaat een conflict wanneer gerepliceerde gegevens een beperking schenden op de tabel waarop ze worden toegepast. Gewoonlijk is de bewerking die dit veroorzaakt INSERT, DELETES of UPDATES die geen effect hebben vanwege ontbrekende rijen en geen conflict veroorzaken. Wanneer er een conflict ontstaat, stopt de replicatie. De logische achtergrondwerker wordt opnieuw gestart in het opgegeven interval (wal_retrieve_retry_interval), maar de replicatie zal opnieuw mislukken totdat de oorzaak van het conflict is opgelost. Dit is een kritieke aandoening die onmiddellijk moet worden aangepakt. Als u dit niet doet, loopt de replicatiesleuf vast op zijn huidige positie begint het uitgeversknooppunt WAL's te verzamelen en onvermijdelijk zal het uitgeversknooppunt geen schijfruimte meer hebben . Een conflict is de meest voorkomende reden waarom replicatie zou kunnen stoppen, maar elke andere foutieve voorwaarde zal hetzelfde effect hebben:b.v. we hebben een nieuwe NOT NULL-kolom toegevoegd aan een geabonneerde tabel, maar zijn vergeten een standaardwaarde te definiëren, of we hebben een kolom toegevoegd aan een gepubliceerde tabel, maar zijn vergeten deze te definiëren in de geabonneerde tabel, of we hebben een fout gemaakt in het type en de twee typen zijn dat niet compatibel. Al die fouten zullen de replicatie stoppen. Er zijn twee manieren om een ​​conflict op te lossen:

  1. Los het werkelijke probleem op
  2. Sla de mislukte transactie over door pg_replication_origin_advance te bellen

Oplossing b. zoals hier ook wordt getoond, kan gevaarlijk en lastig zijn, omdat het in feite een proces van vallen en opstaan ​​is, en als iemand de huidige LSN op de uitgever kiest, kan hij / zij gemakkelijk eindigen met een kapot replicatiesysteem omdat er bewerkingen kunnen zijn tussen de problematische LSN en de huidige LSN die we zouden willen behouden. Dus de beste manier is om het probleem aan de abonneezijde daadwerkelijk op te lossen. bijv. als zich een schending van de UNIEKE SLEUTEL voordoet, kunnen we de gegevens van de abonnee bijwerken of de rij verwijderen. In een productieomgeving moet dit allemaal geautomatiseerd of in ieder geval semi-geautomatiseerd zijn.

De uitgevers- en abonneeknooppunten instellen

Lees deze blog voor een algemeen overzicht van de logische replicatie in de praktijk.

De relevante parameters voor logische replicatie zijn:

  • Uitgeverskant
    • wal_level>=“logisch”
    • max_replication_slots>=#subscriptions + initiële tafelsynchronisatie
    • max_wal_senders>=max_replication_slots + other_physical_standbys
  • Abonneezijde
    • max_replication_slots>=#abonnementen
    • max_logical_replication_workers>=#subscriptions + initiële tabelsynchronisatie
    • max_worker_processes>=max_logical_replication_workers + 1 + max_parallel_workers

We zullen ons concentreren op de speciale overwegingen die voortvloeien uit ons speciale doel waarvoor we logische replicatie nodig hebben om te bereiken:een testdatabasecluster maken voor gebruik door de testafdeling . De publicatie kan voor alle tabellen of per tabel worden gedefinieerd. Ik raad de tafel voor tafel benadering aan, omdat dit ons maximale flexibiliteit geeft. De algemene stappen kunnen als volgt worden samengevat:

  • Voer een nieuwe initdb uit op het abonneeknooppunt
  • Dump het schema van het uitgeverscluster en kopieer naar het abonneeknooppunt
  • Maak het schema op de abonnee
  • Beslis welke tafels je wel en niet nodig hebt.

Met betrekking tot het bovenstaande opsommingsteken zijn er twee redenen waarom u misschien geen tabel hoeft te repliceren of in te stellen voor replicatie:

  • Het is een dummy-tabel zonder belang (en misschien moet je hem ook uit productie halen)
  • is een tabel die lokaal is voor de productieomgeving, wat betekent dat het volkomen logisch is dat dezelfde tabel in de testomgeving (abonnee) zijn eigen gegevens heeft

Alle tabellen die deelnemen aan de logische replicatie moeten een REPLICA IDENTITY hebben. Dit is standaard de PRIMAIRE SLEUTEL, en indien niet beschikbaar kan een UNIEKE sleutel worden gedefinieerd. Volgende stap om de status van de tabellen te vinden met betrekking tot REPLICA IDENTITY.

  • Zoek de tabellen zonder duidelijke kandidaat voor 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') ;
  • Zoek de tabellen zonder PRIMAIRE SLEUTEL maar met een UNIEKE 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';
  • Ga door de bovenstaande lijsten en beslis wat je met elke tafel gaat doen
  • Maak de publicatie aan met de tabellen waarvoor een PK bestaat
    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
  • Maak vervolgens het abonnement aan op het abonneeknooppunt
    create subscription data_for_testdb_pub CONNECTION 'dbname=yourdb host=yourdbhost user=repmgr' PUBLICATION data_for_testdb_pub ;
    Het bovenstaande kopieert ook de gegevens.
  • Voeg tabellen toe die u wilt en die een UNIEKE index hebben
    Draai zowel in uitgevers- als abonneeknooppunten, bijv.:
    ALTER TABLE someschema.yourtable REPLICA IDENTITY USING INDEX yourindex_ukey;
    Over de uitgever:
    ALTER PUBLICATION data_for_testdb_pub ADD TABLE ONLY someschema.yourtable;
    Op de abonnee:
    ALTER SUBSCRIPTION data_for_testdb_pub REFRESH PUBLICATION WITH ( COPY_DATA );
  • Op dit punt (synchronisatie) moet u altijd het PostgreSQL-logboek op het abonneeknooppunt in de gaten houden. U wilt geen fouten of iets anders (time-out) die de voortzetting van logische replicatie verbieden. LOS ELKE FOUT ONMIDDELLIJK OP , of de uitgever blijft WAL-bestanden verzamelen in pg_wal en heeft uiteindelijk onvoldoende ruimte. Je hebt dus te maken met
    • Alle FOUTEN of elk bericht met betrekking tot de logische werker die resulteert in afsluiten
    • Zorg ook voor
      • wal_receiver_timeout
      • wal_sender_timeout

Nadat u alle problemen hebt opgelost, zou uw abonneeknooppunt probleemloos moeten werken. Dus de volgende vraag is hoe dit te gebruiken als een testdatabaseserver. U zult met die problemen/problemen te maken krijgen:

  1. Anonimisering
  2. Primaire sleutels en unieke sleutels die zijn gebaseerd op reeksovertredingen
  3. Een algemene reeks goede praktijken
  4. Bewaking

Anonimisering

Met betrekking tot de anonimisering van persoonlijke gegevens die wordt afgedwongen door de AVG in de EU, moet u ALTIJD een aantal triggers schrijven die alle velden met betrekking tot adressen, bankrekeningen, burgerlijke staat, telefoonnummers, e-mails, enz. leegmaken. Raadpleeg uw beveiligingsfunctionaris in uw bedrijf over wat te bewaren en wat te wissen. De triggers moeten worden gedefinieerd als ALTIJD aangezien de logische werker de instructies uitvoert als REPLICA.

Primaire toetsen met reeksen

Wat betreft sequenties, er zal duidelijk een probleem zijn met die toetsen, tenzij deze worden aangepakt voordat een test wordt gestart. Beschouw dit geval:

  • Op vrijdagmiddag voer je wat tests uit op de abonneedatabase en voeg je een nieuwe rij toe aan een tabel. Dit heeft als ID de volgende waarde die door de reeks wordt gegenereerd.
  • Je gaat naar huis voor het weekend.
  • Een productiegebruiker voert een rij in dezelfde tabel in de uitgeversdatabase in.
  • De rij wordt gerepliceerd op basis van de REPLICA IDENTITY naar het abonneeknooppunt, maar zal mislukken vanwege een PK-fout ERROR. De logische achtergrondwerker wordt afgesloten en probeert het opnieuw. Maar zal blijven mislukken zolang het probleem aanhoudt.
  • De replicatie blijft hangen. Het replicatieslot begint WAL's te verzamelen.
  • De uitgever heeft onvoldoende schijfruimte.
  • In het weekend krijg je een e-mail dat je primaire node in paniek is geraakt!

Dus, om het volgordeprobleem op te lossen, kun je de volgende benadering volgen:

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

Wat het bovenstaande doet, is reeksen instellen op een waarde die groot genoeg is, zodat ze in de toekomst nooit overlappen voor een redelijk groot venster, zodat u een probleemloze testserver hebt.

Een reeks goede praktijken

Je moet je programmeurs echt vertellen dat ze hun tests niet-persistent moeten maken. Dus elke test nadat deze is voltooid, moet de database in dezelfde staat achterlaten als vóór de test. Met op volgorde gebaseerde ID's-inserties is dit geen probleem, we zagen eerder een oplossing. Maar met niet-sequentiële (bijv. samengestelde) UNIEKE sleutels kan dat een probleem zijn. Het is dus het beste om die testgegevens te verwijderen voordat een productierij met dezelfde waarde de geabonneerde tabel bereikt.

Hier moeten we ook het omgaan met schemawijzigingen toevoegen. Alle schemawijzigingen moeten ook op de abonnee worden gedaan om gerepliceerd DML-verkeer niet te onderbreken.

Download de whitepaper vandaag PostgreSQL-beheer en -automatisering met ClusterControlLees wat u moet weten om PostgreSQL te implementeren, bewaken, beheren en schalenDownload de whitepaper

Bewaking

U moet echt investeren in een goede monitoringoplossing. U moet controleren op ...

Bij de abonnee:

  • ALLE berichten in het logboek van de abonnee die relevant zijn voor het afsluiten van de logische werker. Het installeren van een tool als tail_n_mail kan hier echt bij helpen. Een configuratie waarvan bekend is dat deze werkt:
    INCLUDE: ERROR:  .*publisher.*
    INCLUDE: ERROR:  .*exited with exit.*
    INCLUDE: LOG:  .*exited with exit.*
    INCLUDE: FATAL:  
    INCLUDE: PANIC:
    Zodra we een waarschuwing krijgen van tail_n_mail, moeten we het probleem onmiddellijk oplossen.
  • pg_stat_subscription. Pid mag niet nul zijn. Ook moet de vertraging klein zijn.

Bij de uitgever:

  • pg_stat_replicatie. Dit moet zoveel rijen hebben als ze zouden moeten zijn:één voor elke aangesloten standby-stand voor streamingreplicatie (inclusief abonneeknooppunten en andere fysieke standbys).
  • pg_replication_slots voor het abonneeslot. Dit zou actief moeten zijn.

Over het algemeen duurt het even voordat u uw ideale testdatabase-server zonder problemen hebt draaien, maar als u ze allemaal hebt opgelost, zullen uw programmeurs u dankbaar zijn dat u deze heeft!


  1. Een processor selecteren voor SQL Server 2014 – deel 1

  2. Een lijst<> invoegen in de SQL Server-tabel

  3. Alle records verwijderen behalve de meest recente?

  4. Actieve sessies en status van SQL Server