2ndQuadrant » PostgreSQL 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 Replica Logica su PostgreSQL 10 https://blog.2ndquadrant.it/replica-logica-su-postgresql-10/ https://blog.2ndquadrant.it/replica-logica-su-postgresql-10/#comments Thu, 25 Jan 2018 11:21:33 +0000 http://blog.2ndquadrant.it/?p=2989 Logical Replication

Tra le novità introdotte da PostgreSQL 10 sicuramente una delle più importanti è l’implementazione della replica logica nel core di Postgres.

Molti di voi avranno già provato o almeno sentito parlare di pglogical, estensione di PostgreSQL che fornisce il supporto per la replica logica, che, grazie al logical decoding dei WAL (presente dalla 9.4), permette di replicare una selezione di tabelle da un database ad un altro.

In questo articolo vedremo come adesso questo è possibile con PostgreSQL 10 e quali sono le differenze con pglogical. Inoltre, viene assunto che il lettore abbia una preparazione di base sulle nozioni di amministrazione di PostgreSQL e di manipolazione dei file di configurazione e di sicurezza.

replica_logica

Cos’è?

La replica logica si basa sull’architettura Pubblicazione/Sottoscrizione, si differenziano quindi due ruoli: un publisher e un subscriber. A differenza di quella fisica nella quale vengono replicate tutte le modifiche a livello binario, la replica logica permette di filtrare i cambiamenti da replicare scegliendo le tabelle e una combinazione di operazioni su di esse tra UPDATE, INSERT e/o DELETE. Per esempio è possibile replicare solo le UPDATE di una singola tabella da un server ad un altro a scopo di analisi e/o di aggregazione dei dati.

Come funziona

Sul publisher viene definita una “pubblicazione”, ovvero una selezione delle tabelle (o tutte) di un database a cui vengono associate le operazioni da replicare ai subscriber. Grazie alla decodifica logica dei WAL le operazioni sono ricostruite traducendo il codice binario e vengono selezionate solo quelle definite nella “pubblicazione” per essere trasmesse ai subscriber.

Configurazione

L’installazione di default predispone già impostate alcune delle opzioni necessarie a configurare la replica logica.

Per quanto riguarda il publisher:

  • max_replication_slots = 10
    Almeno uno per ogni subscriber più alcuni per l’inizializzazione delle tabelle.
  • max_wal_senders = 10
    Almeno uno per ogni replication_slot più quelli necessari per le repliche fisiche (es.: Barman).

Per quanto riguarda il subscriber:

  • max_logical_replication_workers = 4
    Uno per sottoscrizione, più alcuni da considerare per la sincronizzazione delle tabelle.
  • max_worker_processes = 10
    Almeno uno per ogni replication workers più uno.

[NOTA] Queste però non bastano per attivare la replica logica. Quello che manca, infatti, sono le informazioni all’interno del codice dei WAL necessarie per ricostruire le operazioni da filtrare e inviare ai subscriber. Per ottenere queste informazioni è necessario impostare sul publisher il parametro wal_level a logical e avviare (o riavviare) il servizio.

L’unico cambiamento che dobbiamo apportare è il seguente parametro sul publisher pippo-pg10:

  • wal_level = logical

I valori preimpostati sono più che sufficienti per questo test. Tuttavia, va tenuto conto che sono parametri che vengono valorizzati all’avvio del servizio e quindi ogni ulteriore cambiamento viene applicato solo dopo un nuovo riavvio. In questa ottica è consigliabile impostare valori adeguati al numero di pubblicazioni e sottoscrizioni previsti, prima di dover riavviare il servizio in produzione.

Preparazione

Consideriamo un caso reale di utilizzo della replica logica, prendendo di esempio un cluster con due server PostgreSQL 10:

  • pippo-pg10, ip: 192.168.42.110, publisher
  • paperino-pg10, ip: 192.168.42.210, subscriber

Sul server pippo-pg10 sono presenti le tabelle che devono essere replicate su un database del server paperino-pg10, precedentemente create con pgbench, un tool molto utile per misurare le prestazioni di PostgreSQL.

[root@pippo-pg10 ~]# sudo -iu postgres
-bash-4.2$ psql
psql (10beta4)
Type "help" for help.
postgres=# \c pgbench
You are now connected to database "pgbench" as user "postgres".
pgbench=# \d
               List of relations
 Schema |       Name       | Type  |   Owner
--------+------------------+-------+------------
 public | pgbench_accounts | table | user_bench
 public | pgbench_branches | table | user_bench
 public | pgbench_history  | table | user_bench
 public | pgbench_tellers  | table | user_bench
(4 rows)

Creazione Tabelle

A causa delle restrizioni sulla replicazione non è possibile replicare la definizione di una tabella tanto meno di un database. Per questo occorre replicare manualmente la definizione sul server di sottoscrizione, per esempio partendo da un dump dello schema del database pgbench dal publisher:

-bash-4.2$ pg_dump -s -f pgbench.sql

Quindi creare l’utente e il database di destinazione nell’istanza PostgreSQL di paperino-pg10 (operazioni assenti nello script appena estratto):

[root@paperino-pg10 ~]# sudo -iu postgres
-bash-4.2$ createuser user_bench
-bash-4.2$ createdb pgbench -O user_bench

[NOTA] Non è necessario che l’utente e il database abbiano lo stesso nome, ma in questo caso si utilizza lo stesso nome per semplicità.

Adesso è possibile applicare lo script SQL sul server paperino-pg10:

-bash-4.2$ psql -d pgbench  < pgbench.sql
SET
SET
SET
SET
SET
SET
SET
SET
SET
CREATE EXTENSION
COMMENT
SET
SET
SET
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
CREATE TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

Creazione Ruolo Replicazione

Nell’istanza pippo-pg10 è necessario creare il ruolo dedicato alla replicazione e definire opportunamente la regola nel pg_hba.conf che permetta la connessione dal subscriber paperino-pg10.

pgbench=# create role replica superuser replication;
CREATE ROLE

Creazione Pubblicazione

Una pubblicazione è definita come un set di cambiamenti su una o più tabelle appartenenti ad un solo database. Si possono creare più pubblicazioni in un solo database scegliendo di replicare una tra le operazioni di INSERT, UPDATE e DELETE o una loro combinazione. Ogni tabella può appartenere a più pubblicazioni e una singola pubblicazione può avere più sottoscrizioni.

In questo esempio assumiamo di voler replicare tutte le operazioni di modifica su tutte le tabelle di un database. Per creare questo tipo di pubblicazione è necessario essere superutenti (maggiori dettagli):

pgbench=# CREATE PUBLICATION pgbench_alltables FOR ALL TABLES;
CREATE PUBLICATION

Creazione Sottoscrizione

Una sottoscrizione viene definita su un nodo PostgreSQL, chiamato subscriber, con una connection string verso il server publisher e una lista di una o più pubblicazioni alle quali sottoscriversi. Il nome della sottoscrizione viene trasmesso al publisher come riconoscimento della connessione se non è definito il campo application_name nella stringa di connessione.

Per creare una sottoscrizione è necessario essere superutenti (maggiori dettagli).

Su paperino-pg10:

pgbench=# CREATE SUBSCRIPTION pgbench_rep CONNECTION 'dbname=pgbench host=192.168.42.110 user=replica' PUBLICATION pgbench_alltables;
NOTICE:  created replication slot "pgbench_rep" on publisher
CREATE SUBSCRIPTION

[NOTA] Un replication slot viene creato per ogni sottoscrizione, più uno temporaneo per la sincronizzazione iniziale dei dati.

Adesso è possibile controllare che l’inizializzazione dei dati nel subscriber rispecchi la situazione nel publisher:

sul publisher pippo-pg10

postgres=# \c pgbench
You are now connected to database "pgbench" as user "postgres".
pgbench=# select * from pg_publication;
      pubname      | pubowner | puballtables | pubinsert | pubupdate | pubdelete
-------------------+----------+--------------+-----------+-----------+-----------
 pgbench_alltables |       10 | t            | t         | t         | t
(1 row)
pgbench=# select * from pgbench_branches limit 5;
 bid | bbalance | filler
-----+----------+--------
   1 |        0 |
   2 |        0 |
   3 |        0 |
   4 |        0 |
   5 |        0 |
(5 rows)

pgbench=# select * from pgbench_tellers limit 5;
 tid | bid | tbalance | filler
-----+-----+----------+--------
   1 |   1 |        0 |
   2 |   1 |        0 |
   3 |   1 |        0 |
   4 |   1 |        0 |
   5 |   1 |        0 |
(5 rows)

e sul subscriber paperino-pg10

postgres=# \c pgbench
You are now connected to database "pgbench" as user "postgres".
pgbench=# select * from pg_subscription;
 subdbid |   subname   | subowner | subenabled |                   subconninfo                   | subslotname | subsynccommit |   subpublications
---------+-------------+----------+------------+-------------------------------------------------+-------------+---------------+---------------------
   16532 | pgbench_rep |       10 | t          | dbname=pgbench host=192.168.42.110 user=replica | pgbench_rep | off           | {pgbench_alltables}
(1 row)
pgbench=# select * from pgbench_branches limit 5;
 bid | bbalance | filler
-----+----------+--------
   1 |        0 |
   2 |        0 |
   3 |        0 |
   4 |        0 |
   5 |        0 |
(5 rows)

pgbench=# select * from pgbench_tellers limit 5;
 tid | bid | tbalance | filler
-----+-----+----------+--------
   1 |   1 |        0 |
   2 |   1 |        0 |
   3 |   1 |        0 |
   4 |   1 |        0 |
   5 |   1 |        0 |
(5 rows)

Le tabelle sul server paperino-pg10 sono state inizializzate!

Test Replica

Il test consiste nel verificare che le modifiche apportate alle tabelle sul server pippo-pg10 siano effettivamente replicate su paperino-pg10.

Su pippo-pg10:

pgbench=# BEGIN;
BEGIN
pgbench=# SELECT * FROM pgbench_accounts WHERE aid = 1;
 aid | bid | abalance |                                        filler
-----+-----+----------+--------------------------------------------------------------------------------------
   1 |   1 |        0 |
(1 row)

pgbench=# UPDATE pgbench_accounts SET filler = 'Jonny was here' WHERE aid = 1;
UPDATE 1
pgbench=# select * from pgbench_accounts where aid = 1;
 aid | bid | abalance |                                        filler
-----+-----+----------+--------------------------------------------------------------------------------------
   1 |   1 |        0 | Jonny was here
(1 row)
pgbench=# COMMIT;
COMMIT
pgbench=#

Una volta eseguito il COMMIT nel WAL viene scritta l’operazione UPDATE appena eseguita e replicata al subscriber:

pgbench=# select * from pgbench_accounts where aid = 1;
 aid | bid | abalance |                                        filler
-----+-----+----------+--------------------------------------------------------------------------------------
   1 |   1 |        0 | Jonny was here
(1 row)

Attenzione! Le operazioni di UPDATE e DELETE sono replicate al subscriber solo sulle tabelle che possiedono una REPLICA IDENTITY, che di default è la chiave primaria. La tabella history di pgbench non sarebbe stata replicata in caso avessimo creato una pubblicazione limitata alle UPDATE e/o DELETE, perché non possiede una chiave primaria.

Considerazioni Conclusive

Replica Logica vs. Replica Fisica

La replica logica a differenza della replica fisica di un’istanza in hot-standby mode, non è da considerarsi un’architettura Master/Standby in quanto il subscriber è egli stesso un master, permettendo quindi le scritture su tutte le tabelle. Può essere comunque utilizzata in maniera simile usando utenti con permessi di sola lettura sul subscriber fino al prossimo switchover.

Per l’architettura multi-master, nella quale le modifiche vengono effettuate concorrentemente su più nodi, si rimanda alla lettura del sistema BDR.

Questa tecnologia permette di migrare da una major version di PostgreSQL ad un’altra, al contrario della replica fisica a causa dell’incompatibilità binaria tra differenti versioni.

Differenze con pglogical

L’implementazione nel core di PostgreSQL 10 della replica logica è un’eredità del progetto pglogical, che, essendo più maturo, possiede molte funzionalità in più. Tra le caratteristiche più importanti di pglogical vi è la possibilità di replicare le modifiche allo schema di un database e le DDL, quindi le definizioni delle tabelle. Inoltre è possibile configurare la risoluzione dei conflitti, mentre con PostgreSQL 10, in caso di conflitto la replica logica si interrompe ed è necessario l’intervento umano per la sua risoluzione. Un’altra funzionalità che rende pglogical molto potente è la possibilità di replicare specifiche righe e/o colonne di una tabella.

Commenti

L’inizializzazione dei dati nelle tabelle del subscriber è una funzionalità molto utile, ma è possibile scegliere di non effettuarla durante la creazione della sottoscrizione.

Anche la replica logica può essere sottoposta alle stesse configurazioni di sincronizzazione delle transazioni tra standby e master, in modo da avere una perdita dati zero. Sono sufficienti gli stessi parametri della replica fisica per ottenere la sincronizzazione tra master e standby.

Nell’esempio di questo articolo, per attivare la replica logica sincrona è sufficiente configurare i seguenti parametri:

synchronous_commit = remote_apply
synchronous_standby_names = pgbench_rep

e riavviare PostgreSQL.

Il valore del parametro synchronous_standby_name corrisponde al nome della sottoscrizione. Maggiori dettagli sulla configurazione del parametro synchronous_standby_names.

Adesso mi rimane una domanda: qual è la differenza di velocità fra la replica fisica e quella logica? Potrebbe essere l’interessante argomento del mio prossimo articolo.

]]>
https://blog.2ndquadrant.it/replica-logica-su-postgresql-10/feed/ 0
PGDay.IT 2016 https://blog.2ndquadrant.it/pgday-it-2016/ https://blog.2ndquadrant.it/pgday-it-2016/#comments Wed, 21 Dec 2016 10:10:23 +0000 http://blog.2ndquadrant.it/?p=2963 img_6093-jpgAnche quest’anno si è svolto il PGDay, evento annuale organizzato dall’ITPUG, l’associazione italiana di PostgreSQL. Nonostante i membri dell’associazione siano sparsi per tutto il territorio nazionale, la decima edizione si è svolta nella città che ha dato i natali all’associazione ITPUG, Prato, la mia città.

Durante la manifestazione ho avuto il piacere di dare il mio contributo alla comunità, presentando un talk riguardo l’installazione di PostgreSQL su Network File System. Nel talk ho raccontato una mia esperienza professionale condivisa con il mio collega Giuseppe Broccolo, nel quale testavamo l’affidabilità di Postgres su NFS.

Condividere la mia esperienza su PostgreSQL con gli altri partecipanti all’evento è stato piacevole e costruttivo.

Ho potuto apprezzare i talk di Denis Gasparin sui diversi tool per l’upgrade tra major release di PostgreSQL oltre al keynote tenuto da Giorgio Roncolato, Direttore Sistemi Informativi ULSS 5 di Arzignano, sulla migrazione all’Open Source, dimostrando quanto i tempi siano maturi anche per le istituzioni, sempre più sensibili all’argomento Software Libero.

Come non menzionare i divertenti talk animati di Mladen Marinovic, coi quali è riuscito a trasmettere l’importanza del testing e della code review intrattenendo la platea e regalando momenti di ilarità.

Manifestazioni di questo tipo permettono la condivisione della conoscenza attraverso i dibattiti e le discussioni che nascono sia al termine di ogni talk che durante i momenti di networking.

L’evento mi ha dato l’oppurtunità di stringere nuove amicizie e di rafforzarne altre già confermate. La giornata si è conclusa con un aperitivo che ha portato ad uno scambio di opinioni, prolungando il tempo di permanenza di alcuni partecipanti.

]]>
https://blog.2ndquadrant.it/pgday-it-2016/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
Rilascio aggiornamenti di sicurezza, 11 agosto 2016 https://blog.2ndquadrant.it/rilascio-aggiornamenti-di-sicurezza-11-agosto-2016/ https://blog.2ndquadrant.it/rilascio-aggiornamenti-di-sicurezza-11-agosto-2016/#comments Thu, 11 Aug 2016 13:00:41 +0000 http://blog.2ndquadrant.it/?p=2897 Il PGDG (PostgreSQL Global Development Group) ha rilasciato un aggiornamento per tutte le versioni del sistema di database PostgreSQL attualmente supportate, composto dalle “minor release” 9.5.4, 9.4.9, 9.3.14, 9.2.18 e 9.1.23.

L’aggiornamento risolve due problemi di sicurezza che causavano rispettivamente un crash del sistema e una escalation delle autorizzazioni. Inoltre corregge altri bug emersi negli ultimi tre mesi. Si incoraggiano gli utenti a pianificare l’aggiornamento dei server alla prima occasione possibile.

Aggiornamenti di sicurezza

Questo aggiornamento risolve due falle di sicurezza:

  • CVE-2016-5423: certain nested CASE expressions can cause the server to crash.
  • CVE-2016-5424: database and role names with embedded special characters can cause triggering code during administrative operations like pg_dumpall.

Il fix del secondo problema aggiunge anche una opzione, --reuse-previous, al comando \connect di psql. Dopo l’aggiornamento, pg_dumpall si rifiuterà di gestire nomi di ruolo e database contenenti un ritorno a capo. Per maggiori informazioni sui bug e sul loro impatto in termini di retro-compabilità, si faccia riferimento alle note di rilascio.

Altre correzioni e miglioramenti

Questo aggiornamento corregge anche un numero di bug emersi e riportati nei mesi precedenti. Alcuni di questi riguardano esclusivamente la 9.5, ma altri si riferiscono a tutte le versioni supportate. La lista di correzioni, in inglese, è la seguente:

  • Fix misbehaviors of IS NULL/IS NOT NULL with composite values
  • Fix three areas where INSERT … ON CONFLICT failed to work properly with other SQL features.
  • Make INET and CIDR data types properly reject bad IPv6 values
  • Prevent crash in close_ps() for NaN input coordinates
  • Avoid possible crash in pg_get_expr()
  • Fix several one-byte buffer over-reads in to_number()
  • Don’t pre-plan query if WITH NO DATA is specified
  • Avoid crash-unsafe state with expensive heap_update() paths
  • Fix hint bit update during WAL replay of row locking operations
  • Avoid unnecessary “could not serialize access” with FOR KEY SHARE
  • Avoid crash in postgres -C when the specified variable is a null string
  • Fix two issues with logical decoding and subtransactions
  • Ensure that backends see up-to-date statistics for shared catalogs
  • Avoid consuming a transaction ID during VACUUM
  • Prevent possible failure when vacuuming multixact IDs in an upgraded database
  • When a manual ANALYZE specifies colums, don’t reset changes_since_analyze
  • Fix ANALYZE’s overestimation of n_distinct for nulls
  • Fix bug in b-tree mark/restore processing
  • Fix building of large (bigger than shared_buffers) hash indexes
  • Prevent infinite loop in GiST index build with NaN values
  • Fix possible crash during a nearest-neighbor indexscan
  • Fix “PANIC: failed to add BRIN tuple” error
  • Prevent possible crash during background worker shutdown
  • Many fixes for issues in parallel pg_dump and pg_restore
  • Make pg_basebackup accept -Z 0 as no compression
  • Make regression tests safe for Danish and Welsh locales

La libreria client libpq è stata aggiornata per supportare il nuovo formato di versioning di PostgreSQL che sarà composto soltanto da due parti e non più tre come ora (e.g.: 10.0 invece di 9.5.4). Questo aggiornamento contiene anche la release 2016f di tzdata, con aggiornamenti per Kemerovo, Novosibirsk, Azerbaijan, Bielorussia e Marocco.

Uscita dal supporto comunitario per la versione 9.1

La versione 9.1 uscirà dal supporto comunitario a settembre 2016 (EOL, End-of-Life). Di conseguenza, questo aggiornamento sarà probabilmente l’ultimo per questa versione. Gli utenti di PostgreSQL 9.1 dovrebbero iniziare a pianificare un aggiornamento a una versione più recente prima di tale data. Si vedano le policy di versioning per maggiori informazioni sulle date di fine supporto comunitario delle varie versioni di PostgreSQL.

Istruzioni di aggiornamento

Come ogni aggiornamento di minor release, non è necessario eseguire alcun dump e restore dei database e neppure utilizzare pg_upgrade per effettuare questi ultimi aggiornamenti; è sufficiente spegnere il servizio PostgreSQL ed aggiornare i binari. Gli utenti che hanno saltato aggiornamenti precedenti, potrebbero necessitare di ulteriori operazioni da eseguire dopo l’aggiornamento; si vedano le varie note di rilascio per maggiori dettagli.

Link utili

]]>
https://blog.2ndquadrant.it/rilascio-aggiornamenti-di-sicurezza-11-agosto-2016/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
Rilasciato Barman 1.6.1 https://blog.2ndquadrant.it/rilasciato-barman-1-6-1/ https://blog.2ndquadrant.it/rilasciato-barman-1-6-1/#comments Mon, 23 May 2016 09:00:06 +0000 http://blog.2ndquadrant.it/?p=2837 2ndQuadrant è orgogliosa di annunciare la release 1.6.1 di Barman, il tool per il Backup e la Recovery Manager di PostgreSQL.

Questa minor release consolida il ruolo centrale di Barman nelle installazioni di business continuity di database PostgreSQL e ora permette agli utenti di implementare i comandi per il restore remoto in parallelo su server in standby e durante la recovery.

Inoltre, attraverso il nuovo comando ‘replication-status’, Barman diventa uno strumento molto pratico per il monitoraggio della replica in streaming di ogni server che gestisce.

Sono stati implementati anche altri importanti miglioramenti e sono state effettuate alcune correzioni di bug minori. Per maggiori informazioni, leggi l’annuncio completo oltre all’articolo in inglese scritto dal nostro Gabriele ‘Waiting for Barman 1.6.1‘.

Cos’è Barman

Barman (Backup And Recovery Manager per PostgreSQL) è un software open-source scritto in Python. Permette di eseguire backup remoti su più server in ambienti business critical e di supportare gli amministratori di database durante la fase di recovery. Le funzionalità più apprezzate di Barman sono: cataloghi di backup, backup incrementale, retention policy, backup remoto e recovery, archiviazione e compressione dei file WAL e backup. Barman è progettato, implementato e mantenuto da 2ndQuadrant Italia e distribuito secondo licenza GNU GPL 3.

]]>
https://blog.2ndquadrant.it/rilasciato-barman-1-6-1/feed/ 0
Proroga scadenza della Call for Paper per la Conferenza 5432…MeetUs! https://blog.2ndquadrant.it/proroga-scadenza-della-call-for-paper-per-la-conferenza-5432-meetus/ https://blog.2ndquadrant.it/proroga-scadenza-della-call-for-paper-per-la-conferenza-5432-meetus/#comments Tue, 01 Mar 2016 08:40:43 +0000 http://blog.2ndquadrant.it/?p=2802 Il termine per la partecipazione con l’invio di un abstract alla Conferenza 5432…MeetUs! è stato prorogato alle ore 23:59 del 14 marzo 2016.

La seconda edizione del 5432… MeetUs! si terrà a Milano, il 28 e 29 giugno 2016.

Se ancora non hai risposto alla “Call for Paper”, sei ancora in tempo!topics-it

Tante le proposte pervenute, alcuni Ospiti e Testimonial di PostgreSQL hanno già confermato la loro presenza. I primi sponsor stanno già dando il loro supporto alla Conferenza.

E tra gli speaker che saranno selezionati potresti esserci proprio tu!

Ti rinnoviamo l’invito: se stai realizzando qualcosa di interessante con PostgreSQL, ti invitiamo ad inviarci una proposta di talk!

La proposta deve contenere un abstract che racconti gli aspetti fondamentali ed i punti salienti del talk che vorresti presentare, una breve biografia correlata di fotografia e i dati dei social ed email che vuoi rendere pubblici.

Topics

  • Sistemi operativi
  • Container
  • Hardware e benchmark
  • Configuration manager
  • Devops
  • Sistemi di monitoraggio
  • Virtualization tool
  • GIS
  • PostGIS
  • Continuous integration
  • Linguaggi di programmazione
  • Ricerca e insegnamento con PostgreSQL
  • Derivati e fork commerciali
  • Cloud Integrazioni con altri software
  • Migrazioni da altri database
  • Modello di business open source
  • Casi di studio
  • Hosting

Non aspettare troppo! Inviaci la tua proposta di talk!

]]>
https://blog.2ndquadrant.it/proroga-scadenza-della-call-for-paper-per-la-conferenza-5432-meetus/feed/ 0