Progetto

Generale

Profilo

Actions

Replicazione di PostgresSQL

ATTENZIONE: questo articolo è una bozza, al momento è nello stato di insieme di appunti sparsi senza un'ordine specifico

PostgreSQL supporta diversi meccanismi di replicazione, tratteremo in questo articolo solo uno di questi, la cosiddetta streaming replication.

Verificare le configurazioni

Per verificare il funzionamento delle configurazioni sul master si può eseguire:

postgres=# select * from pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid              | 356531
usesysid         | 16384
usename          | replication
application_name | 13/main
client_addr      | 192.168.50.71
client_hostname  | 
client_port      | 39320
backend_start    | 2022-05-11 16:19:06.618997+02
backend_xmin     | 
state            | streaming
sent_lsn         | 0/50008A0
write_lsn        | 0/50008A0
flush_lsn        | 0/50008A0
replay_lsn       | 0/50008A0
write_lag        | 
flush_lag        | 
replay_lag       | 
sync_priority    | 0
sync_state       | async
reply_time       | 2022-05-12 17:23:56.62433+02

e si verificano i replication slot con:

postgres=# select * from pg_replication_slots;
-[ RECORD 1 ]-------+------------
slot_name           | replication
plugin              | 
slot_type           | physical
datoid              | 
database            | 
temporary           | f
active              | t
active_pid          | 356531
xmin                | 
catalog_xmin        | 
restart_lsn         | 0/50008A0
confirmed_flush_lsn | 
wal_status          | reserved
safe_wal_size       | 

Per verificare il funzionamento delle configurazioni sullo slave si può eseguire:

postgres=# select * from pg_stat_wal_receiver;
-[ RECORD 1 ]---------+---------------------------------------------------------
pid                   | 367679
status                | streaming
receive_start_lsn     | 0/5000000
receive_start_tli     | 1
written_lsn           | 0/50008A0
flushed_lsn           | 0/50008A0
received_tli          | 1
last_msg_send_time    | 2022-05-12 17:25:56.929438+02
last_msg_receipt_time | 2022-05-12 17:25:56.926351+02
latest_end_lsn        | 0/50008A0
latest_end_time       | 2022-05-11 17:53:50.803351+02
slot_name             | replication
sender_host           | 192.168.50.69
sender_port           | 5432
conninfo              | user=replication password=********  [...]

Come ripristinare una replica

Se per un qualunque motivo la streaming replication si interrompe (la ragione più comune è che non si è previsto sul primario la retention di un sufficiente numero di segmenti WAL a coprire le differenze da trasmettere al secondario) occorre ripristinare manualmente da zero la stessa. Per questo motivo è sempre opportuno abilitare sul master l'uso di un replication slot .

Per farlo è disponibile, a partire dalla versione 9.4 di PostgreSQL il comando pg_basebackup (si legga la documentazione su https://www.postgresql.org/docs/10/app-pgbasebackup.html) che consente di eseguire il ripristino direttamente dal secondario. I passi da seguire per farlo sono i seguenti:

  • fermare Postgres con:
    service postgresql stop
    
  • vuotare la directory dei dati (o spostarne i contenuti altrove):
    mkdir oldpgdir/
    mv /var/lib/postgresql/9.6/main/* oldpgdir/
    
  • collegarsi con l'utente postgres:
    su postgres
    
  • ripristinare il DB e la replicazione con:
    pg_basebackup -h IP.DEL.DB.MASTER -U replication -D /var/lib/postgresql/9.6/main/ -P -Xs -R -S 'slot_name'
    

    quest'ultimo comando chiederà la password dell'utente replication usato per gestire la replicazione e provvederà alla ricostruzione (si ometta -S 'slot_name' se non si è creato un replication slot) .
  • riavviare Postgres con:
    service postgresql start
    

Verifica dello stato della replicazione

Ci sono una serie di comandi per verificare lo stato della replicazione. Anzitutto si vada sullo slave e si verifichi che sia in standby mode con (si assume di essere entrati in visualizzazione espansa con \x on):

postgres=# SELECT pg_is_in_recovery();
-[ RECORD 1 ]-----+--
pg_is_in_recovery | t

si può controllare lo stato della ricezione dei dati dal master (da postgres 9.6) con:

postgres=# select * from pg_stat_wal_receiver;
-[ RECORD 1 ]---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
pid                   | 25684
status                | streaming
receive_start_lsn     | 7E/57000000
receive_start_tli     | 1
received_lsn          | 7E/58B33BA8
received_tli          | 1
last_msg_send_time    | 2020-02-19 17:57:20.239628+01
last_msg_receipt_time | 2020-02-19 17:57:20.238761+01
latest_end_lsn        | 7E/58B33BA8
latest_end_time       | 2020-02-19 17:57:20.239628+01
slot_name             | 
conninfo              | user=replication password=******** ....

e si può controllare quanto è passato dall'ultimo replay della replicazione con:

postgres=# select now()-pg_last_xact_replay_timestamp();
-[ RECORD 1 ]------------
?column? | 00:00:05.55037

ma questa indicazione, se non è successo nulla sul master, non è significativa, perché registra solo quando è stata fatta l'ultima modifica rispetto ad adesso, che può essere avvenuto anche parecchio indietro nel tempo se nel frattempo non c'era nulla da modificare.

Per dare una indicazione dell'eventuale ritardo rispetto al master si può (su postgres 9.6) usare qualcosa del tipo:

postgres=# SELECT CASE WHEN pg_last_xlog_receive_location() = pg_last_xlog_replay_location()
                  THEN 0
                ELSE EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())
              END AS log_delay;
-[ RECORD 1 ]
log_delay | 0

mentre a partire da postgres 10 (i nomi delle funzioni sono cambiati) si può usare:

SELECT CASE WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn()                        
                  THEN 0                                                                        ELSE EXTRACT (EPOCH FROM now() - pg_last_xact_replay_timestamp())                              
              END AS log_delay;

Aggiornato da Simone Piccardi quasi 2 anni fa · 6 revisions