PostgreSQL är en av de mest avancerade databaserna med öppen källkod i världen med många fantastiska funktioner. En av dem är Streaming Replication (Physical Replication) som introducerades i PostgreSQL 9.0. Den är baserad på XLOG-poster som överförs till destinationsservern och appliceras där. Det är dock klusterbaserat och vi kan inte replikera en enda databas eller ett enda objekt (selektiv replikering). Under åren har vi varit beroende av externa verktyg som Slony, Bucardo, BDR, etc för selektiv eller partiell replikering eftersom det inte fanns någon funktion på kärnnivån förrän PostgreSQL 9.6. PostgreSQL 10 kom dock med en funktion som heter logisk replikering, genom vilken vi kan utföra replikering på databas-/objektnivå.
Logisk replikering replikerar ändringar av objekt baserat på deras replikeringsidentitet, som vanligtvis är en primärnyckel. Det skiljer sig från fysisk replikering, där replikering är baserad på block och byte-för-byte-replikering. Logisk replikering behöver inte en exakt binär kopia på destinationsserversidan, och vi har möjlighet att skriva på destinationsservern till skillnad från fysisk replikering. Denna funktion kommer från den pglogiska modulen.
I det här blogginlägget kommer vi att diskutera:
- Hur det fungerar - Arkitektur
- Funktioner
- Användningsfall – när det är användbart
- Begränsningar
- Hur du uppnår det
Hur det fungerar - logisk replikeringsarkitektur
Logisk replikering implementerar ett publicerings- och prenumerationskoncept (Publication &Subscription). Nedan finns ett arkitektoniskt diagram på högre nivå om hur det fungerar.
Grundläggande logisk replikeringsarkitektur
Publicering kan definieras på huvudservern och noden på vilken den är definierad kallas "utgivaren". Publicering är en uppsättning ändringar från en enda tabell eller grupp av tabeller. Den är på databasnivå och varje publikation finns i en databas. Flera tabeller kan läggas till i en enda publikation och en tabell kan finnas i flera publikationer. Du bör lägga till objekt uttryckligen till en publikation förutom om du väljer alternativet "ALLA TABELLER" som behöver en superanvändarbehörighet.
Du kan begränsa ändringarna av objekt (INSERT, UPDATE och DELETE) som ska replikeras. Som standard replikeras alla operationstyper. Du måste ha en replikeringsidentitet konfigurerad för objektet som du vill lägga till i en publikation. Detta för att replikera UPDATE- och DELETE-operationer. Replikeringsidentiteten kan vara en primärnyckel eller ett unikt index. Om tabellen inte har en primärnyckel eller unikt index, kan den ställas in på replikidentitet "full" där den tar alla kolumner som nyckel (hela raden blir nyckel).
Du kan skapa en publikation med SKAPA PUBLIKATION. Några praktiska kommandon behandlas i avsnittet "Hur man uppnår det".
Prenumeration kan definieras på destinationsservern och noden på vilken den är definierad kallas "abonnenten". Anslutningen till källdatabasen definieras i prenumerationen. Prenumerantnoden är densamma som alla andra fristående postgres-databas, och du kan också använda den som en publikation för ytterligare prenumerationer.
Prenumerationen läggs till med CREATE SUBSCRIPTION och kan stoppas/återupptas när som helst med kommandot ALTER SUBSCRIPTION och tas bort med DROP SUBSCRIPTION.
När en prenumeration har skapats, kopierar logisk replikering en ögonblicksbild av data i utgivardatabasen. När det är gjort, väntar den på deltaändringar och skickar dem till prenumerationsnoden så snart de inträffar.
Men hur samlas ändringarna in? Vem skickar dem till målet? Och vem tillämpar dem på målet? Logisk replikering är också baserad på samma arkitektur som fysisk replikering. Det implementeras av "walsender" och "apply" processer. Eftersom det är baserat på WAL-avkodning, vem startar avkodningen? Walsender-processen är ansvarig för att starta logisk avkodning av WAL och laddar standardinsticksprogrammet för logisk avkodning (pgoutput). 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 streaming-replikeringsprotokollet till appliceringsarbetaren, som mappar data till lokala tabeller och tillämpar de individuella ändringarna när de tas emot, i korrekt transaktionsordning.
Den loggar alla dessa steg i loggfiler när den ställs in. Vi kan se meddelandena i avsnittet "Hur man uppnår det" längre fram i inlägget.
Funktioner för logisk replikering
- Logisk replikering replikerar dataobjekt baserat på deras replikeringsidentitet (vanligtvis en
- primär nyckel eller unikt index).
- Destinationsserver kan användas för att skriva. Du kan ha olika index och säkerhetsdefinitioner.
- Logisk replikering har stöd för flera versioner. Till skillnad från strömmande replikering kan logisk replikering ställas in mellan olika versioner av PostgreSQL (> 9.4 dock)
- Logisk replikering utför händelsebaserad filtrering
- Jämfört har logisk replikering mindre skrivförstärkning än strömmande replikering
- Publikationer kan ha flera prenumerationer
- Logisk replikering ger lagringsflexibilitet genom att replikera mindre uppsättningar (även partitionerade tabeller)
- Minsta serverbelastning jämfört med triggerbaserade lösningar
- Tillåter parallell streaming mellan utgivare
- Logisk replikering kan användas för migrering och uppgraderingar
- Datatransformation kan göras under installationen.
Användningsfall – När är logisk replikering användbar?
Det är mycket viktigt att veta när man ska använda logisk replikering. Annars får du inte mycket nytta om ditt användningsfall inte stämmer överens. Så här är några användningsfall om när man ska använda logisk replikering:
- Om du vill konsolidera flera databaser till en enda databas för analytiska ändamål.
- Om ditt krav är att replikera data mellan olika större versioner av PostgreSQL.
- Om du vill skicka inkrementella ändringar i en enskild databas eller en delmängd av en databas till andra databaser.
- Om du ger åtkomst till replikerad data till olika grupper av användare.
- Om du delar en delmängd av databasen mellan flera databaser.
Begränsningar för logisk replikering
Logisk replikering har några begränsningar som gemenskapen kontinuerligt arbetar på för att övervinna:
- Tabell måste ha samma fullständiga kvalificerade namn mellan publicering och prenumeration.
- Tabeller måste ha primärnyckel eller unik nyckel
- Ömsesidig (dubbelriktad) replikering stöds inte
- Replicerar inte schema/DDL
- Replicerar inte sekvenser
- Replicerar inte TRUNCATE
- Replicerar inte stora objekt
- Prenumerationer kan ha fler kolumner eller annan ordning på kolumner, men typerna och kolumnnamnen måste matcha mellan publicering och prenumeration.
- Superanvändarrättigheter för att lägga till alla tabeller
- Du kan inte strömma över till samma värd (prenumerationen kommer att låsas).
Hur man uppnår logisk replikering
Här är stegen för att uppnå grundläggande logisk replikering. Vi kan diskutera mer komplexa scenarier senare.
-
Initiera två olika instanser för publicering och prenumeration och starta.
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
-
Parametrar som ska ändras innan du startar instanserna (för både publikations- och prenumerationsinstanser).
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
Andra parametrar kan vara standard för grundläggande inställningar.
-
Ändra filen pg_hba.conf för att tillåta replikering. Observera att dessa värden är beroende av din miljö, men detta är bara ett grundläggande exempel (för både publikations- och prenumerationsinstanser).
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$
-
Skapa ett par testtabeller för att replikera och infoga vissa data på publikationsinstansen.
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=#
-
Skapa struktur för tabellerna på prenumerationsinstansen eftersom logisk replikering inte replikerar strukturen.
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=#
-
Skapa publikation på publikationsinstans (port 5555).
source_rep=# CREATE PUBLICATION mypub FOR TABLE test_rep, test_rep_other; CREATE PUBLICATION Time: 3.840 ms source_rep=#
-
Skapa prenumeration på Prenumerationsinstans (port 5556) på publikationen som skapades i steg 6.
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
Från logg:
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
Som du kan se i NOTICE-meddelandet skapade den en replikeringsplats som säkerställer att WAL-rensningen inte bör göras förrän initiala ögonblicksbilder eller deltaändringar har överförts till måldatabasen. Sedan började WAL-avsändaren avkoda ändringarna och logisk replikering fungerade då både pub och sub startas. Sedan startar den tabellsynkroniseringen.
-
Verifiera data på prenumerationsinstansen.
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=#
Som du ser har data replikerats genom den första ögonblicksbilden.
-
Verifiera deltaändringar.
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$
Det här är stegen för en grundläggande installation av logisk replikering.