PostgreSQL is een van de meest geavanceerde open source databases ter wereld met veel geweldige functies. Een daarvan is Streaming Replication (Physical Replication) die werd geïntroduceerd in PostgreSQL 9.0. Het is gebaseerd op XLOG-records die worden overgebracht naar de doelserver en daar worden toegepast. Het is echter clustergebaseerd en we kunnen geen enkele database of een enkel object (selectieve replicatie) replicatie uitvoeren. Door de jaren heen zijn we afhankelijk geweest van externe tools zoals Slony, Bucardo, BDR, enz. voor selectieve of gedeeltelijke replicatie, aangezien er geen functie op het kernniveau was tot PostgreSQL 9.6. PostgreSQL 10 kwam echter met een functie genaamd Logische replicatie, waarmee we replicatie op database-/objectniveau kunnen uitvoeren.
Logische replicatie repliceert wijzigingen van objecten op basis van hun replicatie-identiteit, wat meestal een primaire sleutel is. Het is anders dan fysieke replicatie, waarbij replicatie gebaseerd is op blokken en byte-by-byte replicatie. Logische replicatie heeft geen exacte binaire kopie nodig aan de kant van de doelserver, en we hebben de mogelijkheid om op de doelserver te schrijven, in tegenstelling tot fysieke replicatie. Deze functie is afkomstig van de pglogical-module.
In deze blogpost gaan we het hebben over:
- Hoe het werkt - Architectuur
- Functies
- Gebruikssituaties - wanneer het nuttig is
- Beperkingen
- Hoe dit te bereiken
Hoe het werkt - Architectuur voor logische replicatie
Logical Replication implementeert een publish en subscribe concept (Publication &Subscription). Hieronder vindt u een architectonisch diagram van een hoger niveau over hoe het werkt.
Basis logische replicatie-architectuur
Publicatie kan worden gedefinieerd op de hoofdserver en het knooppunt waarop het is gedefinieerd, wordt de "uitgever" genoemd. Publicatie is een reeks wijzigingen van een enkele tabel of een groep tabellen. Het is op databaseniveau en elke publicatie bestaat in één database. Aan één publicatie kunnen meerdere tabellen worden toegevoegd en een tabel kan in meerdere publicaties voorkomen. U moet objecten expliciet aan een publicatie toevoegen, behalve als u de optie "ALLE TABELLEN" kiest waarvoor een superuser-privilege vereist is.
U kunt de wijzigingen van objecten (INSERT, UPDATE en DELETE) die moeten worden gerepliceerd, beperken. Standaard worden alle bewerkingstypen gerepliceerd. U moet een replicatie-identiteit hebben geconfigureerd voor het object dat u aan een publicatie wilt toevoegen. Dit is om de UPDATE- en DELETE-bewerkingen te repliceren. De replicatie-identiteit kan een primaire sleutel of een unieke index zijn. Als de tabel geen primaire sleutel of unieke index heeft, kan deze worden ingesteld om de identiteit "volledig" te kopiëren, waarbij alle kolommen als sleutel worden gebruikt (hele rij wordt sleutel).
U kunt een publicatie maken met CREATE PUBLICATION. Enkele praktische commando's worden behandeld in het gedeelte "Hoe dit te bereiken".
Abonnement kan worden gedefinieerd op de doelserver en het knooppunt waarop het is gedefinieerd, wordt de "abonnee" genoemd. De verbinding met de brondatabase wordt gedefinieerd in abonnement. Het abonneeknooppunt is hetzelfde als elke andere stand-alone postgres-database en u kunt het ook gebruiken als publicatie voor verdere abonnementen.
Het abonnement wordt toegevoegd met CREATE ABONNEMENT en kan op elk moment worden gestopt/hervat met de opdracht ALTER ABONNEMENT en verwijderd met DROP ABONNEMENT.
Zodra een abonnement is gemaakt, kopieert Logische replicatie een momentopname van de gegevens in de uitgeversdatabase. Zodra dat is gebeurd, wacht het op deltawijzigingen en stuurt deze naar het abonnementsknooppunt zodra ze zich voordoen.
Hoe worden de wijzigingen echter verzameld? Wie stuurt ze naar het doel? En wie past ze toe op het doelwit? Logische replicatie is ook gebaseerd op dezelfde architectuur als fysieke replicatie. Het wordt geïmplementeerd door "walsender" en "apply" -processen. Aangezien het gebaseerd is op WAL-decodering, wie begint de decodering? Het walsender-proces is verantwoordelijk voor het starten van logische decodering van de WAL en laadt de standaard logische decoderingsplug-in (pgoutput). De plug-in transformeert de gelezen wijzigingen van WAL naar het logische replicatieprotocol en filtert de gegevens volgens de publicatiespecificatie. De gegevens worden vervolgens continu overgedragen met behulp van het streaming-replicatieprotocol naar de toepassingswerker, die de gegevens toewijst aan lokale tabellen en de individuele wijzigingen toepast zodra ze worden ontvangen, in de juiste transactievolgorde.
Het registreert al deze stappen in logbestanden tijdens het instellen. We kunnen de berichten in het gedeelte 'Hoe dit te bereiken' verderop in het bericht zien.
Kenmerken van logische replicatie
- Logische replicatie repliceert gegevensobjecten op basis van hun replicatie-identiteit (meestal een
- primaire sleutel of unieke index).
- Bestemmingsserver kan worden gebruikt voor schrijfbewerkingen. U kunt verschillende indexen en beveiligingsdefinities hebben.
- Logische replicatie heeft ondersteuning voor meerdere versies. In tegenstelling tot streaming-replicatie, kan logische replicatie worden ingesteld tussen verschillende versies van PostgreSQL (> 9.4 echter)
- Logische replicatie maakt filtering op basis van gebeurtenissen
- In vergelijking heeft logische replicatie minder schrijfversterking dan streamingreplicatie
- Publicaties kunnen meerdere abonnementen hebben
- Logische replicatie biedt opslagflexibiliteit door het repliceren van kleinere sets (zelfs gepartitioneerde tabellen)
- Minimale serverbelasting vergeleken met op triggers gebaseerde oplossingen
- Laat parallelle streaming tussen uitgevers toe
- Logische replicatie kan worden gebruikt voor migraties en upgrades
- Gegevenstransformatie kan worden gedaan tijdens het instellen.
Gebruiksscenario's - Wanneer is logische replicatie nuttig?
Het is erg belangrijk om te weten wanneer u logische replicatie moet gebruiken. Anders heb je niet veel voordeel als je use case niet overeenkomt. Dus, hier zijn enkele voorbeelden van wanneer logische replicatie moet worden gebruikt:
- Als u meerdere databases wilt consolideren in één database voor analytische doeleinden.
- Als het uw vereiste is om gegevens te repliceren tussen verschillende hoofdversies van PostgreSQL.
- Als u incrementele wijzigingen in een enkele database of een subset van een database naar andere databases wilt verzenden.
- Als u toegang geeft tot gerepliceerde gegevens aan verschillende groepen gebruikers.
- Als een subset van de database wordt gedeeld tussen meerdere databases.
Beperkingen van logische replicatie
Logische replicatie heeft enkele beperkingen waaraan de gemeenschap voortdurend werkt om deze te overwinnen:
- Tabellen moeten dezelfde volledige naam hebben tussen publicatie en abonnement.
- Tabellen moeten een primaire sleutel of unieke sleutel hebben
- Wederzijdse (bidirectionele) replicatie wordt niet ondersteund
- Repliceert geen schema/DDL
- Repliceert geen reeksen
- Repliceert TRUNCATE niet
- Repliceert geen grote objecten
- Abonnementen kunnen meer kolommen of een andere volgorde van kolommen hebben, maar de typen en kolomnamen moeten overeenkomen tussen publicatie en abonnement.
- Superuser-rechten om alle tabellen toe te voegen
- Je kunt niet naar dezelfde host streamen (abonnement wordt geblokkeerd).
Logische replicatie bereiken
Hier zijn de stappen om basis logische replicatie te bereiken. We kunnen later over complexere scenario's praten.
-
Initialiseer twee verschillende instanties voor publicatie en abonnement en begin.
C1MQV0FZDTY3:bin bajishaik$ export PATH=$PWD:$PATH C1MQV0FZDTY3:bin bajishaik$ which psql /Users/bajishaik/pg_software/10.2/bin/psql C1MQV0FZDTY3:bin bajishaik$ ./initdb -D /tmp/publication_db C1MQV0FZDTY3:bin bajishaik$ ./initdb -D /tmp/subscription_db
-
Parameters die moeten worden gewijzigd voordat u de instanties start (voor zowel publicatie- als abonnementsinstanties).
C1MQV0FZDTY3:bin bajishaik$ tail -3 /tmp/publication_db/postgresql.conf listen_addresses='*' port = 5555 wal_level= logical C1MQV0FZDTY3:bin bajishaik$ pg_ctl -D /tmp/publication_db/ start waiting for server to start....2018-03-21 16:03:30.394 IST [24344] LOG: listening on IPv4 address "0.0.0.0", port 5555 2018-03-21 16:03:30.395 IST [24344] LOG: listening on IPv6 address "::", port 5555 2018-03-21 16:03:30.544 IST [24344] LOG: listening on Unix socket "/tmp/.s.PGSQL.5555" 2018-03-21 16:03:30.662 IST [24345] LOG: database system was shut down at 2018-03-21 16:03:27 IST 2018-03-21 16:03:30.677 IST [24344] LOG: database system is ready to accept connections done server started C1MQV0FZDTY3:bin bajishaik$ tail -3 /tmp/subscription_db/postgresql.conf listen_addresses='*' port=5556 wal_level=logical C1MQV0FZDTY3:bin bajishaik$ pg_ctl -D /tmp/subscription_db/ start waiting for server to start....2018-03-21 16:05:28.408 IST [24387] LOG: listening on IPv4 address "0.0.0.0", port 5556 2018-03-21 16:05:28.408 IST [24387] LOG: listening on IPv6 address "::", port 5556 2018-03-21 16:05:28.410 IST [24387] LOG: listening on Unix socket "/tmp/.s.PGSQL.5556" 2018-03-21 16:05:28.460 IST [24388] LOG: database system was shut down at 2018-03-21 15:59:32 IST 2018-03-21 16:05:28.512 IST [24387] LOG: database system is ready to accept connections done server started
Andere parameters kunnen standaard zijn voor basisinstellingen.
-
Wijzig het bestand pg_hba.conf om replicatie toe te staan. Houd er rekening mee dat deze waarden afhankelijk zijn van uw omgeving, maar dit is slechts een eenvoudig voorbeeld (voor zowel publicatie- als abonnementsinstanties).
C1MQV0FZDTY3:bin bajishaik$ tail -1 /tmp/publication_db/pg_hba.conf host all repuser 0.0.0.0/0 md5 C1MQV0FZDTY3:bin bajishaik$ tail -1 /tmp/subscription_db/pg_hba.conf host all repuser 0.0.0.0/0 md5 C1MQV0FZDTY3:bin bajishaik$ psql -p 5555 -U bajishaik -c "select pg_reload_conf()" Timing is on. Pager usage is off. 2018-03-21 16:08:19.271 IST [24344] LOG: received SIGHUP, reloading configuration files pg_reload_conf ---------------- t (1 row) Time: 16.103 ms C1MQV0FZDTY3:bin bajishaik$ psql -p 5556 -U bajishaik -c "select pg_reload_conf()" Timing is on. Pager usage is off. 2018-03-21 16:08:29.929 IST [24387] LOG: received SIGHUP, reloading configuration files pg_reload_conf ---------------- t (1 row) Time: 53.542 ms C1MQV0FZDTY3:bin bajishaik$
-
Maak een aantal testtabellen om gegevens te repliceren en in te voegen in de publicatie-instantie.
postgres=# create database source_rep; CREATE DATABASE Time: 662.342 ms postgres=# \c source_rep You are now connected to database "source_rep" as user "bajishaik". source_rep=# create table test_rep(id int primary key, name varchar); CREATE TABLE Time: 63.706 ms source_rep=# create table test_rep_other(id int primary key, name varchar); CREATE TABLE Time: 65.187 ms source_rep=# insert into test_rep values(generate_series(1,100),'data'||generate_series(1,100)); INSERT 0 100 Time: 2.679 ms source_rep=# insert into test_rep_other values(generate_series(1,100),'data'||generate_series(1,100)); INSERT 0 100 Time: 1.848 ms source_rep=# select count(1) from test_rep; count ------- 100 (1 row) Time: 0.513 ms source_rep=# select count(1) from test_rep_other ; count ------- 100 (1 row) Time: 0.488 ms source_rep=#
-
Creëer een structuur van de tabellen op de Subscription-instantie, aangezien logische replicatie de structuur niet repliceert.
postgres=# create database target_rep; CREATE DATABASE Time: 514.308 ms postgres=# \c target_rep You are now connected to database "target_rep" as user "bajishaik". target_rep=# create table test_rep_other(id int primary key, name varchar); CREATE TABLE Time: 9.684 ms target_rep=# create table test_rep(id int primary key, name varchar); CREATE TABLE Time: 5.374 ms target_rep=#
-
Publicatie maken op publicatie-instantie (poort 5555).
source_rep=# CREATE PUBLICATION mypub FOR TABLE test_rep, test_rep_other; CREATE PUBLICATION Time: 3.840 ms source_rep=#
-
Maak een abonnement aan op de abonnementsinstantie (poort 5556) op de publicatie die in stap 6 is gemaakt.
target_rep=# CREATE SUBSCRIPTION mysub CONNECTION 'dbname=source_rep host=localhost user=bajishaik port=5555' PUBLICATION mypub; NOTICE: created replication slot "mysub" on publisher CREATE SUBSCRIPTION Time: 81.729 ms
Uit logboek:
2018-03-21 16:16:42.200 IST [24617] LOG: logical decoding found consistent point at 0/1616D80 2018-03-21 16:16:42.200 IST [24617] DETAIL: There are no running transactions. target_rep=# 2018-03-21 16:16:42.207 IST [24618] LOG: logical replication apply worker for subscription "mysub" has started 2018-03-21 16:16:42.217 IST [24619] LOG: starting logical decoding for slot "mysub" 2018-03-21 16:16:42.217 IST [24619] DETAIL: streaming transactions committing after 0/1616DB8, reading WAL from 0/1616D80 2018-03-21 16:16:42.217 IST [24619] LOG: logical decoding found consistent point at 0/1616D80 2018-03-21 16:16:42.217 IST [24619] DETAIL: There are no running transactions. 2018-03-21 16:16:42.219 IST [24620] LOG: logical replication table synchronization worker for subscription "mysub", table "test_rep" has started 2018-03-21 16:16:42.231 IST [24622] LOG: logical replication table synchronization worker for subscription "mysub", table "test_rep_other" has started 2018-03-21 16:16:42.260 IST [24621] LOG: logical decoding found consistent point at 0/1616DB8 2018-03-21 16:16:42.260 IST [24621] DETAIL: There are no running transactions. 2018-03-21 16:16:42.267 IST [24623] LOG: logical decoding found consistent point at 0/1616DF0 2018-03-21 16:16:42.267 IST [24623] DETAIL: There are no running transactions. 2018-03-21 16:16:42.304 IST [24621] LOG: starting logical decoding for slot "mysub_16403_sync_16393" 2018-03-21 16:16:42.304 IST [24621] DETAIL: streaming transactions committing after 0/1616DF0, reading WAL from 0/1616DB8 2018-03-21 16:16:42.304 IST [24621] LOG: logical decoding found consistent point at 0/1616DB8 2018-03-21 16:16:42.304 IST [24621] DETAIL: There are no running transactions. 2018-03-21 16:16:42.306 IST [24620] LOG: logical replication table synchronization worker for subscription "mysub", table "test_rep" has finished 2018-03-21 16:16:42.308 IST [24622] LOG: logical replication table synchronization worker for subscription "mysub", table "test_rep_other" has finished
Zoals u in het NOTICE-bericht kunt zien, heeft het een replicatieslot gecreëerd dat ervoor zorgt dat de WAL-opschoning niet moet worden uitgevoerd voordat de eerste snapshot- of deltawijzigingen zijn overgebracht naar de doeldatabase. Toen begon de WAL-afzender met het decoderen van de wijzigingen, en de toepassing van logische replicatie werkte toen zowel pub als sub werden gestart. Dan start het de tafelsynchronisatie.
-
Controleer gegevens op abonnementsinstantie.
target_rep=# select count(1) from test_rep; count ------- 100 (1 row) Time: 0.927 ms target_rep=# select count(1) from test_rep_other ; count ------- 100 (1 row) Time: 0.767 ms target_rep=#
Zoals u ziet, zijn de gegevens gerepliceerd via de eerste momentopname.
-
Deltawijzigingen verifiëren.
C1MQV0FZDTY3:bin bajishaik$ psql -d postgres -p 5555 -d source_rep -c "insert into test_rep values(generate_series(101,200), 'data'||generate_series(101,200))" INSERT 0 100 Time: 3.869 ms C1MQV0FZDTY3:bin bajishaik$ psql -d postgres -p 5555 -d source_rep -c "insert into test_rep_other values(generate_series(101,200), 'data'||generate_series(101,200))" INSERT 0 100 Time: 3.211 ms C1MQV0FZDTY3:bin bajishaik$ psql -d postgres -p 5556 -d target_rep -c "select count(1) from test_rep" count ------- 200 (1 row) Time: 1.742 ms C1MQV0FZDTY3:bin bajishaik$ psql -d postgres -p 5556 -d target_rep -c "select count(1) from test_rep_other" count ------- 200 (1 row) Time: 1.480 ms C1MQV0FZDTY3:bin bajishaik$
Dit zijn de stappen voor een basisconfiguratie van logische replicatie.