- Q1. PG ha la capacità di memorizzare nella cache/scaldare una relazione?
- Q2. È possibile tornare allo stato precedente della cache in cui era stata lasciata prima di spegnere il server del database a causa della manutenzione?
Nelle versioni precedenti di PostgreSQL, non c'era alcuna possibilità di riscaldare una relazione o memorizzare uno stato della cache, ma da PostgreSQL 9.4 in poi ciascuna delle query precedenti (Q1,Q2) indirizzata con due moduli contrib pg_prewarm e pg_ibernatore . Nonostante siano distinti nella praticità, tuttavia la combinazione sembra essere estremamente praticabile e utile in futuro per i DBA. In breve sui contributi:
pg_prewarm contrib (Autore:Robert Haas), fornisce la capacità di caricare i dati di una relazione nella cache del buffer del sistema operativo o nella cache del buffer PG. Ha la funzionalità del primo o dell'ultimo numero di blocco per il preriscaldamento. (Nota:non ha una protezione speciale sui dati preriscaldati dall'eliminazione della cache e anche se l'istanza del database viene riavviata, è necessario riscaldare le relazioni).
pg_ibernatore contrib (Autore:Gurjeet Singh), fornisce la capacità di salvare automaticamente l'elenco dei contenuti del buffer condiviso su disco all'arresto del database e ripristina automaticamente i buffer all'avvio del database, più o meno come salvare/ripristinare un'istantanea di shared_buffers. Utilizza il modulo PG 9.3 per registrare il "processo di lavoro in background" e genera due processi "Buffer Saver", "Buffer Reader" per il salvataggio/ripristino. È interessante notare che, con un piccolo hack, pg_hibernator può anche consentire allo slave standby di iniziare a servire query a piena velocità con lo stesso contenuto del master, lo vedrà tra un minuto :).
Infine, abbiamo bisogno di pg_buffercache modulo per guardare all'interno del contenuto corrente di PostgreSQL shared_buffers. Questo modulo aiuta a capire quale percentuale di buffer è occupata da una relazione.
Mettiamo in gioco tutti questi contributi e vediamo come servono allo scopo di due domande (Q1, Q2). Userò una tabella "foo" di dimensioni 885 MB sulla mia macchina virtuale locale, insieme a una query pg_buffercache standard.
SELECT c.relname,
count(*) AS buffers
FROM pg_class c
INNER JOIN pg_buffercache b ON b.relfilenode=c.relfilenode AND c.relname='foo'
INNER JOIN pg_database d ON (b.reldatabase=d.oid AND d.datname=current_database())
GROUP BY c.relname
ORDER BY 2 DESC LIMIT 10;
Utilizzo di pg_prewarm contrib e riscaldamento della tabella "pippo".
postgres=# create extension pg_prewarm;
CREATE EXTENSION
postgres=# dt+
List of relations
Schema | Name | Type | Owner | Size | Description
--------+------+-------+----------+--------+-------------
public | foo | table | postgres | 885 MB |
(1 row)
postgres=# select pg_prewarm('foo');
pg_prewarm
------------
113278
(1 row)
--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)
Utilizzo molto semplice e diretto di pg_prewarm con un output di blocchi riscaldati in shared_buffers per la relazione 'foo'. Da pg_buffercache output della query possiamo valutare che ci sono 113278 (113278 * 8 / 1024 =884 MB ) buffer di dimensione del blocco di 8 KB della relazione "foo" che corrisponde all'output di pg_prewarm. Qui, se il server Postgres si riavvia per qualche motivo, shared_buffers sono vuoti e il DBA ha bisogno di riscaldarsi di nuovo per tornare alla fase calda. Per un singolo tavolo, riscaldare è sempre semplice tranne che per un gruppo di tavoli la sua agonia.
A questo punto, possiamo utilizzare pg_hibernator contrib, perché ha la flessibilità di salvare il contenuto di shared_buffer e ripristinarlo all'avvio. Abilitiamo insieme pg_hibernator/pg_prewarm ed eseguiamo un esercizio simile semplicemente includendo un passaggio di riavvio e vediamo se lo stato della cache ritorna così com'è o meno. Non tratterò l'installazione di pg_hibernator, perché su git è molto ben descritto, tuttavia vorrei passare direttamente alla parte di implementazione e avviare il server con pg_hibernator.
postgres 24623 1 0 02:06 pts/4 00:00:00 /usr/local/pgpatch/pg/bin/postgres -D /usr/local/pgpatch/pg/data_10407
postgres 24627 24623 0 02:06 ? 00:00:00 postgres: logger process
postgres 24631 24623 0 02:06 ? 00:00:00 postgres: checkpointer process
postgres 24632 24623 0 02:06 ? 00:00:00 postgres: writer process
postgres 24633 24623 0 02:06 ? 00:00:00 postgres: wal writer process
postgres 24634 24623 0 02:06 ? 00:00:00 postgres: autovacuum launcher process
postgres 24635 24623 0 02:06 ? 00:00:00 postgres: archiver process
postgres 24636 24623 0 02:06 ? 00:00:00 postgres: stats collector process
postgres 24637 24623 0 02:06 ? 00:00:00 postgres: bgworker: Buffer Saver
postgres 24638 24623 11 02:06 ? 00:00:01 postgres: bgworker: Block Reader 2
In database server logs at startup time:
-bash-4.1$ more postgresql-2014-06-02_083033.log
LOG: database system was shut down at 2014-06-02 08:13:00 PDT
LOG: starting background worker process "Buffer Saver"
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
Dal momento che è la prima volta che pg_hibernator è in gioco, puoi vedere due processi e anche registri con alcune informazioni sull'avvio di "Buffer Saver". Ora, preriscalda la relazione "foo" e riavvia il server, in seguito controlla lo stato del buffer se pg_hibernator ha riempito il buffer dove era stato lasciato.
-bash-4.1$ psql -p 10407
psql (9.4beta1)
Type "help" for help.
postgres=# select pg_prewarm('foo');
pg_prewarm
------------
113278
(1 row)
--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)
postgres=# q
-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch/pg/data_10407 stop
waiting for server to shut down.... done
server stopped
-bash-4.1$ ls -l $PGDATA/pg_hibernator/
total 12
-rw------- 1 postgres postgres 160 Jun 3 01:41 1.global.save
-rw------- 1 postgres postgres 915 Jun 3 01:41 2.postgres.save
-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch/pg/data_10407 start
server starting
Abbiamo riavviato il server del database, esaminiamo i log
-bash-4.1$ more postgresql-2014-06-03_020601.log
LOG: database system was shut down at 2014-06-03 02:05:57 PDT
LOG: starting background worker process "Buffer Saver"
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
LOG: registering background worker "Block Reader 2"
LOG: starting background worker process "Block Reader 2"
LOG: Block Reader 2: restored 113433 blocks
LOG: Block Reader 2: all blocks read successfully
LOG: worker process: Block Reader 2 (PID 24638) exited with exit code 1
LOG: unregistering background worker "Block Reader 2"
LOG: registering background worker "Block Reader 1"
LOG: starting background worker process "Block Reader 1"
LOG: Block Reader 1: restored 20 blocks
LOG: Block Reader 1: all blocks read successfully
LOG: worker process: Block Reader 1 (PID 24664) exited with exit code 1
LOG: unregistering background worker "Block Reader 1"
Quindi, "Buffer Reader" ha ripristinato blocchi di 113433 + 20, di cui 113278 appartiene alla relazione "foo". Ottimo, connettiamoci e vediamo.
-bash-4.1$ psql -p 10407
psql (9.4beta1)
Type "help" for help.
--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)
Fantastico... pg_hibernator ha ripristinato lo stato di riscaldamento della cache senza l'interferenza del DBA.
Un altro aspetto positivo di pg_hibernator, uno standby appena creato può avere lo stesso contenuto del buffer condiviso del master, in modo che lo standby possa iniziare a servire le query a piena velocità. Per fare questo esercizio, mentre eseguivo un backup della directory $PGDATA, ho passato SIGTERM al processo "Buffer Saver" in modo che scriva il contenuto dello stato corrente shared_buffers su disco (directory $PGDATA/pg_hibernator) e quindi seguito con l'installazione in standby.
postgres 24637 24623 0 02:06 ? 00:00:00 postgres: bgworker: Buffer Saver
postgres 24653 15179 0 02:06 ? 00:00:01 postgres: wal receiver process streaming 1/6A000A10
postgres 24654 24623 0 02:06 ? 00:00:00 postgres: wal sender process postgres ::1(65011) streaming 1/6A000A10
Dopo l'installazione, il mio slave ha iniziato con lo stesso contenuto del principale
-bash-4.1$ psql -p 10477
psql (9.4beta1)
Type "help" for help.
postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)
Grazie a entrambi gli autori per la meravigliosa estensione sulla memorizzazione nella cache.