PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Memorizzazione nella cache in PostgreSQL

Caching...!!, è un po' difficile fare una breve descrizione di un singolo articolo. Ma proverò a condividere le mie conoscenze apprese da Heikki / Robert Haas / Bruce Momjian in breve. In PostgreSQL, ci sono due livelli, buffer condivisi PG e cache della pagina del sistema operativo, qualsiasi lettura/scrittura dovrebbe passare attraverso la cache del sistema operativo (nessun bypass fino ad ora). Postgres scrive i dati sulla cache della pagina del sistema operativo e conferma all'utente che ha scritto sul disco, successivamente la cache del sistema operativo scrive sul disco fisico al suo ritmo. I buffer condivisi di PG non hanno alcun controllo sulla cache della pagina del sistema operativo e non sanno nemmeno cosa c'è nella cache del sistema operativo. Quindi, la maggior parte dei consigli forniti dai DBA/Professionisti di Postgres per avere DISK più veloce/cache migliore.

Le cache/buffer in PostgreSQL sono più forti come altri database e altamente sofisticati. Come da Oracle background (anche mentalità ... :)), quindi, la mia domanda da chi ho imparato era come/quando/cosa/perché ecc., Per quanto riguarda la cache del buffer del database, i buffer bloccati, lo svuotamento della cache dei buffer del database, il precaricamento del database ecc., Ho ottenuto tutte le mie risposte da loro, tuttavia, l'approccio è leggermente diverso. Sebbene le mie domande fossero infastidite, hanno risposto con grande pazienza e mi hanno chiarito in buona misura che in conseguenza stai leggendo questo blog…. :)..

Su alcuni apprendimenti (ancora in fase di apprendimento), ho tracciato una piccola panoramica di come i dati scorrono tra la memoria e il disco in Postgres e anche alcuni degli strumenti importanti e la NUOVA patch di Robert Haas(pg_prewarm) .

pg_buffercache
Un modulo contrib, che dice cosa c'è nella cache del buffer di PostgreSQL. Installazione di seguito:-

postgres=# CREATE EXTENSION pg_buffercache;

pgfincore
Ha una funzionalità per fornire informazioni su quali dati nella cache delle pagine del sistema operativo. Pgfincore, il modulo diventa molto utile quando viene bastonato con pg_buffercache, ora è possibile ottenere insieme le informazioni sulla cache del buffer PG e sulla cache della pagina del sistema operativo. Grazie a Cerdic Villemain. Pgfincore, backbone è fadvise, fincore che sono linux ftools. Puoi anche usare fincore/fadvise installando source. Due cose, puoi usare pgfincore contrib module o ftools entrambi risultano uguali. Li ho provati entrambi, sono semplicemente fantastici.

Installation:
Download the latest version: http://pgfoundry.org/frs/download.php/3186/pgfincore-v1.1.1.tar.gz
As root user:
export PATH=/usr/local/pgsql91/bin:$PATH //Set the path to point pg_config.
tar -xvf pgfincore-v1.1.1.tar.gz
cd pgfincore-1.1.1
make clean
make
make install

Now connect to PG and run below command

postgres=# CREATE EXTENSION pgfincore;

pg_prewarm
Precaricamento della relazione/indice nella cache del buffer PG. È possibile in PostgreSQL? oh sì, grazie a Robert Haas , che ha recentemente inviato la patch alla community, si spera che possa essere disponibile in PG 9.2 o PG 9.3. Tuttavia, puoi usare la patch per i tuoi test su PG 9.1.

pg_prewarm ha tre MODALITÀ:

  1. PREFETCH: Recupero dei blocchi dati in modo asincrono solo nella cache del sistema operativo non nei buffer PG (solo per la cache del sistema operativo)
  2. LEGGI: Legge tutti i blocchi nel buffer fittizio e forza nella cache del sistema operativo. (solo per la cache del sistema operativo)
  3. BUFFER: legge tutti i blocchi o l'intervallo di blocchi nella cache del buffer del database.

Installazione:
Sto applicando la patch pg_prewarm alla mia installazione del sorgente PG, è necessario modificare secondo la configurazione.

  1. Posizione Untar del sorgente PG:/usr/local/src/postgresql-9.1.3
  2. Posizione installazione PG:/usr/local/pgsql91
  3. Posizione di tutti i download:/usr/local/src

Nota:installa PG prima di applicare la patch pg_prewarm.

1. Scarica la patch in /usr/local/src/location
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
Patch allegata Email:
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2. Dopo il download, vai alla posizione della sorgente PG e segui i passaggi.

# cd /usr/local/src/postgresql-9.1.3
# patch -p1 < ../pg_prewarm.bin         (I have renamed after download)
# make -C contrib/pg_prewarm
# make -C contrib/pg_prewarm install

3. Il comando sopra creerà i file sotto $PGPATH/contrib/extension. Ora sei pronto per aggiungere il modulo di contributo.

postgres=# create EXTENSION pg_prewarm;
CREATE EXTENSION
postgres=# dx
List of installed extensions
Name | Version | Schema | Description
----------------+---------+------------+----------------------------------------
pg_buffercache | 1.0 | public | examine the shared buffer cache
pg_prewarm | 1.0 | public | prewarm relation data
pgfincore | 1.1.1 | public | examine and manage the os buffer cache
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
(4 rows)

Documentation:
/usr/local/src/postgresql-9.1.3/doc/src/sgml
[root@localhost sgml]# ll pgpre*
-rw-r--r-- 1 root root 2481 Apr 10 10:15 pgprewarm.sgml

dstat
Una combinazione di strumenti vmstat, iostat, netstat, top, ecc. in un unico comando linux "dstat". Quando il database si comporta in modo insolito, per conoscere la causa dal livello del sistema operativo, apriamo un paio di terminali per eseguire il pull di processi, memoria, lettura/scrittura del disco, informazioni di rete, il che è un po' doloroso per passare da una finestra all'altra. Quindi, dstat ha opzioni server al suo interno, il che aiuta a mostrare tutti i comandi in un output in una finestra.

Installation:
Dstat download link: (RHEL 6)
wget http://pkgs.repoforge.org/dstat/dstat-0.7.2-1.el6.rfx.noarch.rpm
or
yum install dstat
Documentation: http://dag.wieers.com/home-made/dstat/

Strumenti Linux
È progettato per funzionare con le moderne chiamate di sistema Linux, inclusi mincore, fallocate, fadvise, ecc. Ftools ti aiuterà a capire quali file sono nella cache del sistema operativo. Utilizzando gli script perl/python è possibile recuperare le informazioni sulla cache della pagina del sistema operativo sui file oggetto (pg_class.relfilenode). pg_fincore si basa su questo. Puoi usare gli script pgfincore o ftools.

Installation:
Download the tar.gz from the link.
https://github.com/david415/python-ftools

cd python-ftools
python setup.py build
export PYTHONPATH=build/lib.linux-x86_64-2.5
python setup.py install

Note: You need to have python & psycopg2 installed before installing python-ftools.

Ora, siamo tutti pronti per procedere con l'esempio per verificare con gli strumenti e le utilità. Nel mio esempio, ho una tabella, ha un indice e una sequenza con oltre 100 MB di dati.

postgres=# d+ cache
Table "public.cache"
Column | Type | Modifiers | Storage | Description
--------+---------+-----------------------------------------+----------+-------------
name | text | | extended |
code | integer | | plain |
id | integer | default nextval('icache_seq'::regclass) | plain |
Indexes:
"icache" btree (code)
Has OIDs: no

Interroga per conoscere la dimensione occupata dalla tabella, la sequenza e il suo indice.

postgres=# SELECT c.relname AS object_name,
CASE when c.relkind='r' then 'table'
when c.relkind='i' then 'index'
when c.relkind='S' then 'sequence'
else 'others'
END AS type,pg_relation_size(c.relname::text) AS size, pg_size_pretty(pg_relation_size(c.relname::text)) AS pretty_size
FROM pg_class c
JOIN pg_roles r ON r.oid = c.relowner
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE (c.relkind = ANY (ARRAY['r'::"char", 'i'::"char", 'S'::"char",''::"char"])) AND n.nspname = 'public';

object_name | type | size | pretty_size
-------------+----------+----------+-------------
icache_seq | sequence | 8192 | 8192 bytes
cache | table | 83492864 | 80 MB
icache | index | 35962880 | 34 MB
(3 rows)

Total object size 'cache'

postgres=# select pg_size_pretty(pg_total_relation_size('cache'));
pg_size_pretty
----------------
114 MB
(1 row)

Ho scritto una piccola query clubbing pgfincore e pg_buffercache per estrarre informazioni dal buffer PG e dalla cache della pagina del sistema operativo. Userò questa query nel mio esempio, incollando solo gli output di questa query.

select rpad(c.relname,30,' ') as Object_Name,
case when c.relkind='r' then 'Table' when c.relkind='i' then 'Index' else 'Other' end as Object_Type,
rpad(count(*)::text,5,' ') as "PG_Buffer_Cache_usage(8KB)",
split_part(pgfincore(c.relname::text)::text,','::text,5) as "OS_Cache_usage(4KB)"
from pg_class c inner join pg_buffercache b on b.relfilenode=c.relfilenode
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database() and c.relnamespace=(select oid from pg_namespace where nspname='public'))
group by c.relname,c.relkind
order by "PG_Buffer_Cache_usage(8KB)"
desc limit 10;

object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
(0 rows)

Note: I have bounced the cluster to flush PG buffers & OS Page Cache. So, no data in any Cache/buffer.

Precaricamento della relazione/indice utilizzando pg_prewarm:
Prima, facendo rimbalzare il cluster, ho attivato la query di scansione sequenziale della tabella completa sulla tabella "Cache" e ho notato il tempo che intercorre prima del riscaldamento della relazione/indice.

postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.033..354.691 rows=1600000 loops=1)
Total runtime: 427.769 ms
(2 rows)

Consente di riscaldare relazione/indice/sequenza usando pg_prewarm e controllare il piano di query.

postgres=# select pg_prewarm('cache','main','buffer',null,null);
pg_prewarm
------------
10192
(1 row)
postgres=# select pg_prewarm('icache','main','buffer',null,null);
pg_prewarm
------------
4390
(1 row)

Output of combined buffers:
object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
icache | Index | 4390 | 8780
cache | Table | 10192 | 20384
(2 rows)

output pgfincore:

postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 2
cache | 20384
icache | 8780
(3 rows)

or for each object.

postgres=# select * from pgfincore('cache');
relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit
------------------+---------+--------------+--------------+-----------+-----------+---------------+---------
base/12780/16790 | 0 | 4096 | 20384 | 20384 | 1 | 316451 |
(1 row)

Per recuperare informazioni simili usando lo script python-ftools devi conoscere il numero di relfilenode degli oggetti, controlla di seguito.

postgres=# select relfilenode,relname from pg_class where relname ilike '%cache%';
relfilenode | relname
-------------+----------------
16787 | icache_seq /// you can exclude sequence.
16790 | cache /// table
16796 | icache /// index
(3 rows)

usando lo script python-ftools

Non è interessante….!!!!.
Ora confronta il piano di spiegazione dopo aver riscaldato la tavola nel buffer.

postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.016..141.804 rows=1600000 loops=1)
Total runtime: 215.100 ms
(2 rows)

Come svuotare/preriscaldare una relazione/indicizzare nella cache del sistema operativo?
Utilizzando pgfadvise, puoi precaricare o svuotare la relazione dalla cache del sistema operativo. Per ulteriori informazioni, digitare df pgfadvise* nel terminale per tutte le funzioni relative a pgfadvise. Di seguito è riportato un esempio di svuotamento della cache del sistema operativo.

postgres=# select * from pgfadvise_dontneed('cache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16790 | 4096 | 20384 | 178145
(1 row)
postgres=# select * from pgfadvise_dontneed('icache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16796 | 4096 | 8780 | 187166
(1 row)
postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 0
cache | 0
icache | 0
(3 rows)

Mentre queste cose accadono in una finestra puoi controllare il rapporto di lettura/scrittura usando dstat. Per ulteriori opzioni usa dstat –list
dstat -s –top-io –top-bio –top-mem

Precaricamento dell'intervallo di blocchi utilizzando la funzionalità pg_prewarm dell'intervallo.
Supponiamo, per qualche motivo, di voler far rimbalzare il cluster, ma uno dei tavoli grandi che si trova nel buffer sta funzionando bene. Quando rimbalza, la tua tabella non è più nei buffer, per tornare allo stato originale com'era prima di rimbalzare, devi sapere quanti blocchi di tabella c'erano nei buffer e precaricarli usando l'opzione pg_prewarm range.

Ho creato una tabella interrogando pg_buffercache e successivamente ho inviato informazioni sull'intervallo di blocchi a pg_prewarm. In questo modo, i buffer condivisi sono tornati con la tabella precedentemente caricata al suo interno. Vedi l'esempio.

select c.relname,count(*) as buffers from pg_class c 
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)
Note: These are the blocks in buffer.

postgres=# create table blocks_in_buff (relation, fork, block) as select c.oid::regclass::text, case b.relforknumber when 0 then 'main' when 1 then 'fsm' when 2 then 'vm' end, b.relblocknumber from pg_buffercache b, pg_class c, pg_database d where b.relfilenode = c.relfilenode and b.reldatabase = d.oid and d.datname = current_database() and b.relforknumber in (0, 1, 2);
SELECT 14716

Rimbalza il cluster e precarica l'intervallo di blocchi relativi alla tabella nei buffer da "blocks_in_buff".

postgres=# select sum(pg_prewarm(relation, fork, 'buffer', block, block)) from blocks_in_buff;
sum
-------
14716
(1 row)

postgres=# select c.relname,count(*) as buffers from pg_class c
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)

Vedi, il mio shared_buffer è di nuovo in gioco.

Divertiti…!!! tornerà con cose più interessanti. Pubblica i tuoi commenti.