2ndQuadrant » PostgreSQL 9.6 https://blog.2ndquadrant.it Il blog sui database di 2ndQuadrant Italia Thu, 25 Jan 2018 11:36:59 +0000 en-US hourly 1 http://wordpress.org/?v=4.3.15 PostgreSQL 9.6 “sbarca” a Milano! https://blog.2ndquadrant.it/postgresql-9-6-sbarca-a-milano/ https://blog.2ndquadrant.it/postgresql-9-6-sbarca-a-milano/#comments Thu, 20 Oct 2016 09:49:48 +0000 http://blog.2ndquadrant.it/?p=2949 Il 27 ottobre si svolgerà a Milano un evento dedicato alle novità presenti nella release 9.6 di PostgreSQL rilasciata il 29 settembre scorso.

postgres9-6-milano

L’evento è organizzato dal team italiano di 2ndQuadrant ed è rivolto a tutti gli appassionati di PostgreSQL, ai curiosi ed ai pochi titubanti che ancora non lo hanno adottato.

Il team di 2ndQuadrant, in continua espansione, ha mostrato la sua forte dedizione al progetto, contribuendo fortemente al rilascio di questa nuova ed importante release.

Affronteremo anche altre tematiche, come, ad esempio, l’importanza della corretta architettura a garanzia della business continuity.

L’incontro è gratuito e si svolgerà presso una sede di eccellenza: IBM Client Center.

Se qualcuno si domandasse il perché della sede, forse non ha letto di una importante novità presente nel repository di PostgreSQL per i pacchetti Debian e Ubuntu, disponibili su apt.postgresql.org.

Il 30 settembre è stato pubblicato l’annuncio ufficiale: il repository è stato esteso, rendendo disponibili i pacchetti precompilati per architettura POWER8 Little Endian di IBM.

Questo uno dei motivi per cui abbiamo scelto l’IBM Client Center, oltre al fatto che è nata una collaborazione tra 2ndQuadrant Italia, IBM Italia e IBM Power Systems Linux Center – Montpellier basata sull’intento di fornire a PostgreSQL grossi vantaggi aggiuntivi, magari attraverso l’attivazione di nuovi progetti condivisi.

Come è nostro costume abbiamo anche pensato al momento di networking, con il pranzo a chiusura della mattinata, riservando ampio spazio al libero confronto.

Per partecipare basta iscriversi attraverso Eventbrite. Ci aspettiamo un’ampia partecipazione per dare il benvenuto tutti insieme alla release 9.6 di PostgreSQL: Il database relazionale open source più avanzato.

Vi aspettiamo!

]]>
https://blog.2ndquadrant.it/postgresql-9-6-sbarca-a-milano/feed/ 0
Ritorno al futuro con PostgreSQL, parte 3: Come usare pg_rewind con PostgreSQL 9.6 https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-3-come-usare-pg_rewind-con-postgresql-9-6/ https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-3-come-usare-pg_rewind-con-postgresql-9-6/#comments Mon, 17 Oct 2016 10:25:46 +0000 http://blog.2ndquadrant.it/?p=2936 backtothefuture_03

Questa è la terza ed ultima parte dell’articolo dedicato a pg_rewind. Negli ultimi due abbiamo visto come pg_rewind può essere utile per correggere uno "split-brain" causato erroneamente durante la procedura di scambio dei ruoli tra un master ed uno standby, evitando di dover risincronizzare i nodi tramite un nuovo base backup. Abbiamo anche visto che questo è possibile per cluster di replica semplici che non coinvolgono più di due standby. In questo caso solo due nodi possono essere allineati dopo lo switchover, mentre gli altri necessitano di essere risincronizzati con un base backup. Dalla versione 9.6 di PostgreSQL, adesso è possibile utilizzare pg_rewind su cluster di replica più complessi.

A partire da PostgreSQL 9.6, pg_rewind ha una nuova funzionalità che gli permette di estendere l’orizzonte di visibilità della timeline di un intero cluster di alta disponibilità (HA), come quello di esempio nel mio precedente articolo. Adesso è infatti in grado di individuare il punto più recente nella timeline condiviso tra due o più nodi e risincronizzarli (e non più solo dall’ultimo checkpoint eseguito sul master prima della promozione dello standby, come nella versione 9.5).

Consideriamo quindi lo stesso esempio, ma adesso basato su PostgreSQL 9.6:

~$ # Set PATH variable
~$ export PATH=/usr/pgsql-9.6/bin:${PATH}
~$ 
~$ # This is the directory where we will be working on
~$ # Feel free to change it and the rest of the script
~$ # will adapt itself
~$ WORKDIR=/var/lib/pgsql/9.6
~$ 
~$ # Environment variables for PGDATA and archive directories
~$ MASTER_PGDATA=${WORKDIR}/master
~$ STANDBY1_PGDATA=${WORKDIR}/standby1
~$ STANDBY2_PGDATA=${WORKDIR}/standby2
~$ ARCHIVE_DIR=${WORKDIR}/archive
~$ 
~$ # Create the archive directory
~$ mkdir -p ${ARCHIVE_DIR}
~$ 
~$ # Create the HA cluster
~$ initdb --data-checksums -D ${WORKDIR}/master
~$ cat >> ${MASTER_PGDATA}/postgresql.conf <<EOF
~$ archive_command = 'cp %p ${ARCHIVE_DIR}/%f'
~$ archive_mode = on
~$ wal_level = hot_standby
~$ max_wal_senders = 10
~$ min_wal_size = '32MB'
~$ max_wal_size = '32MB'
~$ hot_standby = on
~$ wal_log_hints = on
~$ EOF
~$ cat >> ${MASTER_PGDATA}/pg_hba.conf <<EOF
~$ # Trust local access for replication
~$ # BE CAREFUL WHEN DOING THIS IN PRODUCTION
~$ local replication replication trust
~$ EOF
~$ pg_ctl -D /var/lib/pgsql/9.6/master -l ${WORKDIR}/master.log start
~$ psql -c "CREATE USER replication WITH replication"
~$ pg_basebackup -D ${STANDBY1_PGDATA} -R -c fast -U replication -x
~$ echo "port = 5433" >> ${STANDBY1_PGDATA}/postgresql.conf
~$ pg_ctl -D ${STANDBY1_PGDATA} -l ${WORKDIR}/standby.log start
~$ pg_basebackup -D ${STANDBY2_PGDATA} -R -c fast -U replication -x
~$ echo "port = 5434" >> ${STANDBY2_PGDATA}/postgresql.conf
~$ pg_ctl -D ${STANDBY2_PGDATA} -l ${WORKDIR}/standby2.log start

Simuliamo una promozione non voluta di uno dei due standby come nuovo master, lasciando gli altri nodi a formare un cluster HA indipendente:

~$ pg_ctl -D ${STANDBY1_PGDATA} promote

Adesso lo standby promosso procede nella timeline 2, mentre gli altri continuano sulla 1.

Completiamo lo "split-brain" creando una nuova tabella sul master che ha ancora in replica il secondo standby, e che non sarà visibile sul nodo appena promosso.

L’obiettivo adesso è quello di ricreare il cluster HA originale, con un master allineato alla situazione precedente lo "split-brain" (ovviamente senza la nuova tabella), che replichi due standby.

Dal momento che pg_rewind, con PostgreSQL 9.6, permette di rendere ogni nodo un master nel cluster HA, l’idea è di:

  1. Fermare gli standby (incluso quello promosso)
  2. Fermare il vecchio master e risincronizzarlo con lo standby promosso tramite pg_rewind
  3. Modificare i parametri port e primary_conninfo nella configurazione (del vecchio master), in modo da seguire lo standby promosso
  4. Risincronizzare l’altro standby con quello promosso usando pg_rewind
  5. Modificarne poi i parametri port e primary_conninfo nella configurazione, in modo da seguire lo standby promosso a nuovo master del cluster HA

Vediamo come:

~$ pg_ctl -D ${STANDBY2_PGDATA} stop
waiting for server to shut down.... done
server stopped
~$ pg_ctl -D ${MASTER_PGDATA} stop
waiting for server to shut down.... done
server stopped
~$ pg_rewind --target-pgdata=${MASTER_PGDATA} --source-server="port=5433 user=postgres dbname=postgres"
servers diverged at WAL position 0/A0002C8 on timeline 1
rewinding from last common checkpoint at 0/A000220 on timeline 1
Done!
~$ pg_rewind --target-pgdata=${STANDBY2_PGDATA} --source-server="port=5433 user=postgres dbname=postgres"
servers diverged at WAL position 0/A0002C8 on timeline 1
rewinding from last common checkpoint at 0/A000220 on timeline 1
Done!

Una volta cambiate le configurazioni del vecchio master e dell’altro standby non promosso, riavviarli:

~$ pg_ctl -D ${MASTER_PGDATA} start
~$ pg_ctl -D ${STANDBY2_PGDATA} start

Adesso tutti e tre i nodi sono attivi e:

  • Esiste un solo master in replica due standby, come all’inizio
  • La tabella creata non è visibile, quindi i dati sono consistenti con la situazione iniziale

Ottimo!! Pensate se avessimo dovuto risincronizzare due nodi utilizzando un backup completo… :S

Conclusioni

pg_rewind è uno degli strumenti più utili in ambito HA: permette di evitare la risincronizzazione tramite l’esecuzione di nuovi base backup, in caso di "split-brain" accidentali. PostgreSQL 9.6 aggiunge nuove e potenti funzionalità a pg_rewind, e permette nel caso di cluster HA complessi di ricreare lo stato originale a seguito di split-brain accidentali, partendo da qualsiasi nodo nel cluster per la resincronizzazione.

Come raccomandazione finale: prendete cura dell’archiviazione dei WAL! Generalmente, con la replica fisica, gli amministratori di database basano la loro architettura in contesto alta disponibilità solo sulla connessione streaming. Per poter usare pg_rewind è necessario aver configurata l’archiviazione dei WAL, in modo da poterli prelevare in caso non siano più presenti sul master. Vi consiglio di considerare l’utilizzo di Barman, e la sua funzionalità get-wal, per facilitare la gestione degli archivi e l’eventuale recupero dei WAl necessari.

]]>
https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-3-come-usare-pg_rewind-con-postgresql-9-6/feed/ 0
Più “potenza” per PostgreSQL https://blog.2ndquadrant.it/piu-potenza-per-postgresql/ https://blog.2ndquadrant.it/piu-potenza-per-postgresql/#comments Fri, 07 Oct 2016 09:28:37 +0000 http://blog.2ndquadrant.it/?p=2925 L’annuncio ufficiale è stato pubblicato venerdì scorso: il repository di PostgreSQL per i pacchetti Debian e Ubuntu, apt.postgresql.org, è stato esteso, rendendo disponibili i pacchetti precompilati per architettura POWER8 Little Endian di IBM. power8-ok

Fantastico, non vi pare?

Quello che pochi sanno è come siamo arrivati ad ottenere questo risultato.

Ingrediente primario: le relazioni umane.

Tutto nasce ad ottobre 2014, durante la conferenza Open Source organizzata da Soiel a Milano. IBM Italia era come noi sponsor del convegno ed i nostri desk erano alquanto vicini.

I talk presentati da ambo le parti hanno dato lo spunto alle prime interazioni, ad un dialogo aperto nel rispetto reciproco.

L’approccio iniziale si è basato su una consapevolezza comune di un mercato IT in continua evoluzione, sempre più orientato verso l’Open Source, dove la crescente richiesta delle aziende è basata sull’affidabilità e sul supporto sia in termini di tecnologie che in termini di piattaforme.

Come i più sanno, IBM ha progettato un’architettura basata su tecnologia open che garantisce performance e sicurezza: IBM Power Systems. Una piattaforma dedicata alle tecnologie Open Source, e, di conseguenza, interessante per PostgreSQL.

Quindi: perché non permettere a PostgreSQL di sfruttare al massimo le prestazioni, la velocità e la potenza che una piattaforma come il Power8 mette a disposizione?

Inizialmente si trattò di effettuare dei test di performance sia della release 9.4 che della release 9.5 di PostgreSQL. Era aprile 2015. Questa fu l’occasione per noi di interagire con i tecnici presenti a Montpellier nell’IBM Power Systems Linux Center.

Il risultato dei  benchmarking fu presentato alla conferenza “5432…MeetUs! – Edizione 2015” proprio da uno dei tecnici di Montpellier, con il quale avevamo potuto interagire fino a quel momento solo da remoto. Un incontro fondamentale, durante il quale nasce l’idea di incrementare il repository di PostgreSQL con i pacchetti Debian e Ubuntu per Power.

Per renderlo fattibile, dovevano essere intraprese delle azioni da entrambe le parte, che richiedevano un’analisi di fattibilità ed una programmazione che non avrebbe portato azioni nell’immediato.

È stato proprio durante l’edizione 2016 della conferenza da noi organizzata “5432…MeetUs!” che sono state gettate le basi solide per lo sviluppo dei pacchetti, oggi disponibili per tutti.

La presenza non solo di IBM Italia, ma anche dei tecnici dell’IBM Power Systems Linux Center di Montpellier, ha concretizzato il progetto, portandolo ad un livello decisamente operativo. Marco Nenciarini, Debian developer e maintainer dei pacchetti distribuiti dalla Comunità di PostgreSQL, afferma: “È stato un piacere per me poter lavorare su un’architettura simile, progettata per carichi che richiedono concorrenza elevata e un’ampia banda di elaborazione dati” – “Poter collaborare con Sébastien Chabrolles di IBM Power Systems Linux Center – Montpellier – è stata un’esperienza fantastica che ha arricchito entrambi.”

Un grazie va anche a credativ, nella fattispecie Christoph Berg, che, nelle ultime settimane, ha collaborato con noi alla messa a punto dell’infrastruttura della Comunità di PostgreSQL per la creazione, il testing e la distribuzione dei pacchetti Debian e Ubuntu su architettura Power.

Per chiudere un grazie a IBM Italia, importante nella realizzazione del progetto, per la sua disponibilità e per averci permesso di incontrare persone fantastiche. Noi tutti in 2ndQuadrant siamo certi che questa collaborazione porterà altri fantastici tasselli alla crescita di PostgreSQL in ambito enterprise.

Da parte nostra, non vediamo l’ora di dare vita a nuovi progetti con IBM Italia e IBM Power Systems Linux Center – Montpellier.
A presto!

]]>
https://blog.2ndquadrant.it/piu-potenza-per-postgresql/feed/ 0
Ritorno al futuro con PostgreSQL, parte 2: Come usare pg_rewind https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-2-come-usare-pg_rewind/ https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-2-come-usare-pg_rewind/#comments Wed, 28 Sep 2016 10:19:58 +0000 http://blog.2ndquadrant.it/?p=2917 backtothefuture_02

Nell’articolo precedente abbiamo visto come funziona pg_rewind per riallineare le timeline di un cluster di replica semplice composto da un master che replica su di un singolo standby. In un tale contesto, in un eventuale switchover, solo due nodi sono chiamati in causa. Ma cosa succede quando iniziano ad esserci diversi nodi di standby, anche in cascata?

Consideriamo adesso un cluster di replica un po’ più complesso, ma sempre basato su PostgreSQL 9.5, nel quale ci sono due standby non in cascata; in modo simile a quanto già fatto nel mio primo articolo dedicato a pg_rewind, creiamo questo cluster. Iniziamo col master:

# Set PATH variable
export PATH=/usr/pgsql-9.5/bin:${PATH}

# This is the directory where we will be working on
# Feel free to change it and the rest of the script
# will adapt itself
WORKDIR=/var/lib/pgsql/9.5

# Environment variables for PGDATA and archive directories
MASTER_PGDATA=${WORKDIR}/master
STANDBY1_PGDATA=${WORKDIR}/standby1
STANDBY2_PGDATA=${WORKDIR}/standby2
ARCHIVE_DIR=${WORKDIR}/archive

# Initialise the cluster
initdb --data-checksums -D ${MASTER_PGDATA}

# Basic configuration of PostgreSQL
cat >> ${MASTER_PGDATA}/postgresql.conf <<EOF
archive_command = 'cp %p ${ARCHIVE_DIR}/%f'
archive_mode = on
wal_level = hot_standby
max_wal_senders = 10
min_wal_size = '32MB'
max_wal_size = '32MB'
hot_standby = on
wal_log_hints = on
EOF

cat >> ${MASTER_PGDATA}/pg_hba.conf <<EOF
# Trust local access for replication
# BE CAREFUL WHEN DOING THIS IN PRODUCTION
local replication replication trust
EOF

# Create the archive directory
mkdir -p ${ARCHIVE_DIR}

# Start the master
pg_ctl -D ${MASTER_PGDATA} -l ${WORKDIR}/master.log start

# Create the replication user
psql -c "CREATE USER replication WITH replication"

E procediamo poi con il primo standby:

# Create the first standby
pg_basebackup -D ${STANDBY1_PGDATA} -R -c fast -U replication -x

cat >> ${STANDBY1_PGDATA}/postgresql.conf <<EOF
port = 5433
EOF

# Start the first standby
pg_ctl -D ${STANDBY1_PGDATA} -l ${WORKDIR}/standby1.log start

In modo identico, creiamo il secondo standby:

# Create the second standby
pg_basebackup -D ${STANDBY2_PGDATA} -R -c fast -U replication -x

cat >> ${STANDBY2_PGDATA}/postgresql.conf <<EOF
port = 5434
EOF

# Start the second standby
pg_ctl -D ${STANDBY2_PGDATA} -l ${WORKDIR}/standby2.log start

Consideriamo anche in questo caso che siano mantenuti pochi WAL sul master (notare come è stato valorizzato il parametro max_wal_size) che vengono opportunamente archiviati.

Se inseriamo un po’ di dati sul master, li vedremo visibili anche su entrambi gli (hot) standby.

Promuoviamo adesso uno dei due standby a nuovo master (ad esempio, quello basato su ${STANDBY1_PGDATA}), lasciando gli altri nodi inalterati:

pg_ctl -D ${STANDBY1_PGDATA} promote

Le modifiche eventualmente apportate al precedente master non saranno visibili sullo standby promosso, mentra saranno visibili sull’altro; nella directory archive/ è possibile trovare il file 00000002.history, che mostra un cambio nella timeline avvenuto durante la promozione, come visto anche nel precedente caso.

Tentiamo adesso di correggere l’errore, ricreando il cluster di replica come in origine, con lo standby promosso come nuovo master e gli altri due nodi come rispettivi standby: la procedurà che cercherò di seguire sarà

  1. spengere il vecchio master e risincronizzarlo a partire dallo standby promosso usando pg_rewind
  2. spengere il secondo standby e risincronizzarlo a partire dallo standby promosso, come fatto nel punto precedente

Iniziamo col primo punto:

~$ pg_ctl -D ${MASTER_PGDATA} stop
waiting for server to shut down.... done
server stopped
~$ pg_rewind --target-pgdata=${MASTER_PGDATA} \
    --source-server="port=5433 user=postgres dbname=postgres"
servers diverged at WAL position 0/501E680 on timeline 1
could not open file "/var/lib/pgsql/9.5/master/pg_xlog/000000010000000000000005": No such file or directory

could not find previous WAL record at 0/501E680
Failure, exiting

Come ci aspettavamo, mancano i WAL! Sì, so di essere ripetitivo, ma come già detto è sempre buona norma archiviare i WAL! Infatti, adesso è possibile recuperare i WAL mancanti: qui la procedurà sarà quella di copiarli manualmente per poi inserirli all’interno della pg_xlog/ del master, per poi rilanciare nuovamente pg_rewind (ma considerate anche l’uso di Barman per questo):

~$ cp ${ARCHIVE_DIR}/00000001000000000000000[56] ${MASTER_PGDATA}/pg_xlog/
~$ pg_rewind --target-pgdata=${MASTER_PGDATA} \
    --source-server="port=5433 user=postgres dbname=postgres"
servers diverged at WAL position 0/501E680 on timeline 1
rewinding from last common checkpoint at 0/501E5D8 on timeline 1
Done!

Ricordiamoci di cambiare opportunamente il parametro primary_conninfo all’interno del file recovery.conf ed il parametro port nel postgresql.conf, ed il vecchio master è ora pronto per seguire lo standby promosso. Facciamo adesso lo stesso anche col secondo standby:

~$ pg_ctl -D ${STANDBY2_PGDATA} stop
waiting for server to shut down.... done
server stopped
~$ pg_rewind --target-pgdata=${STANDBY2_PGDATA} \
    --source-server="port=5433 user=postgres dbname=postgres"
could not find common ancestor of the source and target cluster's timelines
Failure, exiting

Dunque, in questo caso non funziona: il secondo standby deve essere comunque risincronizzato dallo standby promosso tramite un nuovo base backup…

Conclusioni

pg_rewind è molto utile per risincronizzare i nodi tra di loro in un cluster di replica. Tuttavia, per infrastrutture che prevedono più standby non è possibile risincronizzare ogni nodo con solo questo tool.

Nonostante questo l’eventuale downtime degli standby è ridotto: un nodo può essere comunque velocemente riallineato, nell’attesa che gli altri vengano poi man mano aggiunti con nuovi base backup.

PostgreSQL 9.6 introduce una nuova, interessante funzionalità per pg_rewind: il suo orizzonte di visibilità può essere esteso e sarà sempre possibile trovare un punto comune nella timeline di un cluster di replica… non perdere la terza e ultima parte, dedicata alle novità di pg_rewind presenti in PostgreSQL 9.6!

]]>
https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-2-come-usare-pg_rewind/feed/ 0
Ritorno al Futuro con PostgreSQL, parte 1: Introduzione a pg_rewind https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-1-introduzione-a-pg_rewind/ https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-1-introduzione-a-pg_rewind/#comments Mon, 12 Sep 2016 09:00:32 +0000 http://blog.2ndquadrant.it/?p=2906 backtothefuture_01

PostgreSQL 9.5 introduce pg_rewind, un tool per risincronizzare un vecchio master con uno standby promosso che funziona anche se nel frattempo, non volutamente, quest’ultimo ha proseguito nella sua timeline. Questo è il caso, ad esempio, di uno switchover non eseguito con successo.

Avete mai concluso uno switchover con uno “split brain”? Questa situazione succede quando invece che aver invertito i ruoli tra master e standby, ottenete due master ciascuno con la sua propria timeline. È in situazioni come queste che pg_rewind viene in aiuto dei DBA PostgreSQL che si devono confrontare con i problemi di alta disponibilità (HA).

Fino alla versione 9.5 di PostgreSQL c’era una sola soluzione possibile: risincronizzare la PGDATA del vecchio master con un nuovo base backup a partire dallo standby promosso e poi aggiungerlo come nuovo standby al cluster di replica. Questo diventa un problema quando le dimensioni del database sono notevoli: nel caso di diverse centinaia di GB non è semplice effettuare queste operazioni mantenendo allo stesso tempo downtime ridotti.

Riportare un database allo stato in cui si trovava in un determinato momento del passato può essere complicato, ma nonostante questo ci sono varie strategie. Suggerisco a chi è interessato di dare un’occhiata agli articoli di Gulcin che affrontano il tema in PostgreSQL e che menziona anche l’uso di pg_rewind.

Come funziona pg_rewind

pg_rewind è in grado di leggere tutti i file contenuti nella PGDATA del vecchio master, identificare i blocchi modificati durante un eventuale cambio di timeline e quindi copiare solo questi dallo standby promosso, in modo da riallinearsi. Come “effetto collaterale”, anche i file di configurazione vengono copiati e sovrascritti, quindi è compito del DBA quello di riadattarli eventualmente al nodo in esame. Ad ogni modo, questo evita di dover risincronizzare totalmente la PGDATA.

Per fare questo, è necessario avere tutti i WAL prodotti negli ultimi istanti di vita del vecchio master precedenti lo switchover. Le modifiche sono individuate dal confronto tra i blocchi di dati presenti nella PGDATA con le modifiche inserite nei WAL. Una volta identificati i blocchi modificati, vengono sostituiti con quelli presenti nello standby promosso, mimando una sorta di “rewind” della timeline.

Inoltre:

  • le istanze debbono essere state inizializzate con l’opzione “-k” (o --data-checksums)
  • il parametro wal_log_hints deve essere abilitato

Fino a PostgreSQL 9.5, i WAL necessari sono quelli a partire dall’ultimo checkpoint, dato che pg_rewind non è in grado di andare indietro nella timeline ulteriormente.

Per capire meglio come funziona, consideriamo questo semplice esempio:

# Set PATH variable
export PATH=/usr/pgsql-9.5/bin:${PATH}

# This is the directory where we will be working on
# Feel free to change it and the rest of the script
# will adapt itself
WORKDIR=/var/lib/pgsql/9.5

# Environment variables for PGDATA and archive directories
MASTER_PGDATA=${WORKDIR}/master
STANDBY1_PGDATA=${WORKDIR}/standby1
ARCHIVE_DIR=${WORKDIR}/archive

# Initialise the cluster
initdb --data-checksums -D ${MASTER_PGDATA}

# Basic configuration of PostgreSQL
cat >> ${MASTER_PGDATA}/postgresql.conf <<EOF
archive_command = 'cp %p ${ARCHIVE_DIR}/%f'
archive_mode = on
wal_level = hot_standby
max_wal_senders = 10
min_wal_size = '32MB'
max_wal_size = '32MB'
hot_standby = on
wal_log_hints = on
EOF

cat >> ${MASTER_PGDATA}/pg_hba.conf <<EOF
# Trust local access for replication
# BE CAREFUL WHEN DOING THIS IN PRODUCTION
local replication replication trust
EOF

# Create the archive directory
mkdir -p ${ARCHIVE_DIR}

# Start the master
pg_ctl -D ${MASTER_PGDATA} -l ${WORKDIR}/master.log start

# Create the replication user
psql -c "CREATE USER replication WITH replication"

(notare il basso numero di WAL mantenuti volutamente nel master), ed uno standby:

# Create the first standby
pg_basebackup -D ${STANDBY1_PGDATA} -R -c fast -U replication -x

cat >> ${STANDBY1_PGDATA}/postgresql.conf <<EOF
port = 5433
EOF

# Start the first standby
pg_ctl -D ${STANDBY1_PGDATA} -l ${WORKDIR}/standby1.log start

Inseriamo alcuni dati sul master: questi saranno visibili anche dallo (hot) standby.

Promuoviamo adesso lo standby, lasciando inalterato il master:

pg_ctl -D ${STANDBY1_PGDATA} promote

Se adesso aggiorniamo il master i cambiamenti non saranno più visibili dallo standby. Inoltre, nella directory archive/ è presente il file 00000002.history e questo mostra che c’è stato un cambio di timeline durante la promozione.

Proviamo adesso ad effettuare il “rewind” del master, e ad aggiungerlo in replica allo standby promosso:

~$ pg_ctl -D ${MASTER_PGDATA} stop
waiting for server to shut down.... done
server stopped
~$ pg_rewind --target-pgdata=${MASTER_PGDATA} \
    --source-server="port=5433 user=postgres dbname=postgres"

Va notato che per la connessione al server sorgente – lo standby promosso – è stato usato l’utente postgres perché pg_rewind necessita di una connessione tramite superuser per ispezionare i blocchi di dati.

Se il parametro max_wal_size non è sufficientemente alto per mantenere nella pg_xlog/ del (vecchio) master i WAL necessari, come volutamente configurato nel nostro esempio, viene emesso un errore come il seguente:

The servers diverged at WAL position 0/3015938 on timeline 1.
could not open file "/var/lib/pgsql/9.5/master/pg_xlog/000000010000000000000002": No such file or directory

could not find previous WAL record at 0/3015938
Failure, exiting

Ci sono due possibili soluzioni a questo:

  • copiare manualmente i WAL mancanti dall’archivio alla directory pg_xlog/ del master, a partire da quello riportato nel messaggio di errore
  • configurare opportunamente il parametro restore_command all’interno del file recovery.conf da includere nella PGDATA del (vecchio) master, così che pg_rewind troverà automaticamente i WAL mancanti.

La seconda è probabilmente la più adatta. Pensiamo, ad esempio, al caso in cui l’archivio di WAL è gestito tramite Barman: il restore_command potrebbe essere basato sulla funzionalità get-wal di Barman, come chiaramente spiegato in questo interessante articolo di Gabriele. Così facendo, Barman può essere usato come una possibile sorgente da cui prelevare i WAL necessari a pg_rewind.

Una volta che tutti i WAL necessari sono disponibili, pg_rewind può essere nuovamente eseguito, questa volta correttamente, ottenendo il seguente messaggio:

~$ pg_rewind --target-pgdata=${MASTER_PGDATA} \
    --source-server="port=5433 user=postgres dbname=postgres"
servers diverged at WAL position 0/3015938 on timeline 1
rewinding from last common checkpoint at 0/3000140 on timeline 1
Done!

Va ribadito che adesso verranno copiati solo pochi blocchi di dati della PGDATA, quelli modificati durante lo split-brain, anche se il database occupasse centinaia di GB! Ricordiamoci poi che anche le configurazioni sono state copiate e sovrascritte, incluso un eventuale recovery.conf già presente nella PGDATA del vecchio master che deve essere convertito in un nuovo standby. Quindi, **bisogna ricordarsi di*:

  • modificare la porta utilizzata dall’istanza (5432 nel nostro caso) nel postgresql.conf;
  • modificare la primary_conninfo nel recovery.conf in modo da assicurarsi che il vecchio master sia in grado di poter effettuare la connessione streaming verso lo standby promosso a nuovo master.

Una volta che questo è stato fatto, basta far partire nuovamente il vecchio master e questo sarà in grado di seguire in replica quello nuovo.

Avete cluster di replica più complessi di questo basato su due soli nodi? Non preoccupatevi! La seconda parte entrerà ancor più nel dettaglio nel funzionamento di pg_rewind in PostgreSQL 9.5!

]]>
https://blog.2ndquadrant.it/ritorno-al-futuro-con-postgresql-parte-1-introduzione-a-pg_rewind/feed/ 0
PostgreSQL 9.6: sequential scan parallelo https://blog.2ndquadrant.it/postgresql-9-6-sequential-scan-parallelo/ https://blog.2ndquadrant.it/postgresql-9-6-sequential-scan-parallelo/#comments Mon, 11 Jul 2016 07:25:05 +0000 http://blog.2ndquadrant.it/?p=2872 Parallel-Sequential-Scan

Per lungo tempo una delle più note mancanze di PostgreSQL è stata la possibilità di parallelizzare le query. Con l’uscita della versione 9.6 non sarà più così. È stato infatti svolto un grande lavoro sul tema, per il quale il primo risultato è stato il commit 80558c1, in cui viene introdotta la parallelizzazione dei sequential scan in alcuni casi che vedremo nel corso di questo articolo.

Innanzitutto, una premessa: lo sviluppo di questa feature è stato continuo e alcuni parametri hanno cambiato nome nel susseguirsi di commit. L’articolo è stato scritto con un checkout al 17 giugno, e presenta alcune caratteristiche che saranno presenti solo dalla beta2 della 9.6.

Rispetto alla major 9.5 sono stati introdotti nuovi parametri all’interno della configurazione. Questi sono:

  • max_parallel_workers_per_gather: il numero di worker che possono assistere un sequential scan su una tabella;
  • min_parallel_relation_size: la dimensione minima che deve avere una relazione affinché il planner consideri l’uso di worker aggiuntivi;
  • parallel_setup_cost: parametro del planner che valuta il costo di istanziare un worker;
  • parallel_tuple_cost: parametro del planner che valuta il costo di trasferire una tupla da un worker a un altro;
  • force_parallel_mode: parametro utile per i test, forza il parallelismo anche su query su cui il planner agirebbe in altri modi.

Vediamo come i worker aggiuntivi possono essere usati per velocizzare le nostre query. Creiamo una tabella di test con un campo INT e cento milioni di record:

postgres=# CREATE TABLE test (i int);
CREATE TABLE
postgres=# INSERT INTO test SELECT generate_series(1,100000000);
INSERT 0 100000000
postgres=# ANALYSE test;
ANALYZE

Di default PostgreSQL ha max_parallel_workers_per_gather impostato a 2, per cui verranno attivati due worker durante un sequential scan.

Un semplice sequential scan non presenta novità alcuna:

postgres=# EXPLAIN ANALYSE SELECT * FROM test;
                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Seq Scan on test  (cost=0.00..1442478.32 rows=100000032 width=4) (actual time=0.081..21051.918 rows=100000000 loops=1)
 Planning time: 0.077 ms
 Execution time: 28055.993 ms
(3 rows)

È infatti richiesta la presenza di una clausola WHERE per la parallelizzazione:

postgres=# EXPLAIN ANALYZE SELECT * FROM test WHERE i=1;
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..964311.60 rows=1 width=4) (actual time=3.381..9799.942 rows=1 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on test  (cost=0.00..963311.50 rows=0 width=4) (actual time=6525.595..9791.066 rows=0 loops=3)
         Filter: (i = 1)
         Rows Removed by Filter: 33333333
 Planning time: 0.130 ms
 Execution time: 9804.484 ms
(8 rows)

Possiamo tornare al comportamento precedente e osservarne le differenze impostando max_parallel_workers_per_gather a 0:

postgres=# SET max_parallel_workers_per_gather TO 0;
SET
postgres=# EXPLAIN ANALYZE SELECT * FROM test WHERE i=1;
                                               QUERY PLAN
--------------------------------------------------------------------------------------------------------
 Seq Scan on test  (cost=0.00..1692478.40 rows=1 width=4) (actual time=0.123..25003.221 rows=1 loops=1)
   Filter: (i = 1)
   Rows Removed by Filter: 99999999
 Planning time: 0.105 ms
 Execution time: 25003.263 ms
(5 rows)

Un tempo 2.5 volte maggiore.

Non sempre il planner considera un sequential scan parallelo la migliore opzione. Se la query non è abbastanza selettiva e ci sono molte tuple da trasferire, è possibile che sia preferito un sequential scan "classico":

postgres=# SET max_parallel_workers_per_gather TO 2;
SET
postgres=# EXPLAIN ANALYZE SELECT * FROM test WHERE i<90000000;
                                                      QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
 Seq Scan on test  (cost=0.00..1692478.40 rows=90116088 width=4) (actual time=0.073..31410.276 rows=89999999 loops=1)
   Filter: (i < 90000000)
   Rows Removed by Filter: 10000001
 Planning time: 0.133 ms
 Execution time: 37939.401 ms
(5 rows)

Infatti, se proviamo a forzare un sequential scan parallelo, otteniamo un risultato peggiore:

postgres=# SET parallel_tuple_cost TO 0;
SET
postgres=# EXPLAIN ANALYZE SELECT * FROM test WHERE i<90000000;
                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..964311.50 rows=90116088 width=4) (actual time=0.454..75546.078 rows=89999999 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on test  (cost=0.00..1338795.20 rows=37548370 width=4) (actual time=0.088..20294.670 rows=30000000 loops=3)
         Filter: (i < 90000000)
         Rows Removed by Filter: 3333334
 Planning time: 0.128 ms
 Execution time: 83423.577 ms
(8 rows)

Possiamo incrementare il numero di worker fino a raggiungere max_worker_processes (default: 8). Ripristiniamo il valore di parallel_tuple_cost vediamo quello che accade aumentando max_parallel_workers_per_gather a 8.

postgres=# SET parallel_tuple_cost TO DEFAULT ;
SET
postgres=# SET max_parallel_workers_per_gather TO 8;
SET
postgres=# EXPLAIN ANALYZE SELECT * FROM test WHERE i=1;
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..651811.50 rows=1 width=4) (actual time=3.684..8248.307 rows=1 loops=1)
   Workers Planned: 6
   Workers Launched: 6
   ->  Parallel Seq Scan on test  (cost=0.00..650811.40 rows=0 width=4) (actual time=7053.761..8231.174 rows=0 loops=7)
         Filter: (i = 1)
         Rows Removed by Filter: 14285714
 Planning time: 0.124 ms
 Execution time: 8250.461 ms
(8 rows)

Nonostante PostgreSQL potesse usare fino a 8 worker, ne ha instanziati solo 6. Questo perché Postgres ottimizza il numero di worker anche in base alle dimensioni della tabella e al parametro min_parallel_relation_size. Il numero dei worker messi a disposizione da postgres si basa su una successione geometrica di ragione 3 il cui primo termine è min_parallel_relation_size. Facciamo un esempio. Considerando gli 8MB del default del parametro:

Dimensione Worker
<8MB 0
<24MB 1
<72MB 2
<216MB 3
<648MB 4
<1944MB 5
<5822MB 6

Possiamo vedere che, essendo la nostra tabella 3458MB, 6 è il massimo numero di worker disponibili.

postgres=# \dt+ test
                    List of relations
 Schema | Name | Type  |  Owner   |  Size   | Description
--------+------+-------+----------+---------+-------------
 public | test | table | postgres | 3458 MB |
(1 row)

Per concludere, una breve dimostrazione dei miglioramenti ottenuti da attraverso questa patch. Lanciando la nostra query abilitando un numero crescente di worker, otteniamo i seguenti risultati:

Worker Tempo
0 24767.848 ms
1 14855.961 ms
2 10415.661 ms
3 8041.187 ms
4 8090.855 ms
5 8082.937 ms
6 8061.939 ms

Possiamo vedere che i tempi migliorano notevolmente, fino ad arrivare ad un terzo del valore iniziale. È semplice da spiegare anche il fatto che non ci siano miglioramenti fra l’uso di tre e 6 worker: la macchina su cui è stato eseguito il test ha 4 cpu disponibili, per cui dopo 3 worker più il processo originale i risultati si stabilizzano.

Per concludere, con la 9.6 PostgreSQL ha posto le basi per la parallelizzazione delle query, di cui il sequential scan parallelo è solo il primo, ottimo, risultato. Vedremo infatti come sempre nella 9.6 siano state parallelizzate anche le aggregazioni, ma questo è materiale per un altro articolo che uscirà nelle prossime settimane.

]]>
https://blog.2ndquadrant.it/postgresql-9-6-sequential-scan-parallelo/feed/ 0
Backup concorrenti con Barman e PostgreSQL 9.6 https://blog.2ndquadrant.it/backup-concorrenti-con-barman-e-postgresql-9-6/ https://blog.2ndquadrant.it/backup-concorrenti-con-barman-e-postgresql-9-6/#comments Mon, 20 Jun 2016 08:30:20 +0000 http://blog.2ndquadrant.it/?p=2847 Postgres-9.6+b PostgreSQL 9.6 estende il framework disponibile per i backup fisici permettendo agli utenti di eseguire backup in modo concorrente. Barman supporterà questo nuovo set di funzioni in modo trasparente, senza più richiedere l’estensione pgespresso.

L’estensione pgespresso, concepita dal nostro Simon Riggs, consentiva di marcare l’inizio e la fine del processo di backup anche su uno standby in sola lettura. Tramite pgespresso, gli utenti di Barman possono eseguire backup fisici via rsync/Ssh da un server in standby, scaricando la reale copia dal server master.

Questa funzionalità è chiamata backup concorrente ed è già disponibile in PostgreSQL attraverso il protocollo di streaming replication, via pg_basebackup.

La nuova API di PostgreSQL 9.6

L’ultima versione che pgespresso supporterà in termini di backup concorrente è PostgreSQL 9.6. Per quale motivo?

La API che PostgreSQL mette a disposizione per eseguire backup fisici di basso livello è stata estesa in modo da supportare nativamente il backup concorrente (o meglio, dovrei usare il termine “non esclusivo”). Non sono sicuro se Magnus (l’autore di questa patch) sia stato ispirato da pgespresso oppure no, ma ciò che conta è che il suo contributo sia più generico e robusto (dopo tutto, pgespresso è stato progettato per interagire soltanto con Barman).

Pertanto, PostgreSQL 9.6 e versioni future avranno al loro interno funzioni che permetteranno a Barman di richiedere un backup concorrente, rendendo pgespresso non più necessario.

Per maggiori dettagli su questa nuova API, ti consiglio di leggere la sezione che ho scritto nella pagina in inglese del Wiki di PostgreSQL “What’s new in PostgreSQL 9.6”. Per adesso, è importante sapere che:

  • pg_start_backup() è stata modificata e un nuovo parametro adesso permette di specificare se il backup è esclusivo (default, per retro-compatibilità) oppure no;
  • una nuova versione di pg_stop_backup() è stata fornita per i backup concorrenti: da un punto di vista tecnico, questa funzione adesso ritorna il contenuto della backup label e la mappa dei tablespace disponibili.

Barman e il backup concorrente di PostgreSQL 9.6

La cosa rilevante per i nostri cari utenti di Barman è che quest’ultimo gestirà in modo trasparente la nuova API, senza alcun impatto a livello di esperienza utente.

Di default, Barman richiederà un backup esclusivo (utilizzando le funzioni classiche disponibili sin da PostgreSQL 8). Ad ogni modo, puoi scatenare il nuovo comportamento impostando concurrent_backup nell’opzione globale/per server chiamata backup_options, come segue:

backup_options = concurrent_backup

In futuro, PostgreSQL dismetterà le funzioni per il backup esclusivo in favore di quelle per il concorrente, principalmente a causa di alcuni casi limite potenzialmente pericolosi. In particolare, la morte improvvisa di un server PostgreSQL prima di invocare pg_start_backup(), evento che lascia un file backup_label nella directory PGDATA e che impedisce al server di ripartire (e comunque, il comando barman check opportunamente configurato nel tuo sistema di monitoraggio e alerting è in grado di identificare questo problema).

Quando la nuova API per i backup diventerà quella principale per PostgreSQL, Barman agirà di conseguenza. Nel frattempo, ti invito a testare questa nuova funzionalità, attualmente disponibile solo su Github e che farà parte di Barman 1.6.2/1.7.0. Grazie!

]]>
https://blog.2ndquadrant.it/backup-concorrenti-con-barman-e-postgresql-9-6/feed/ 0