PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Mise en cache dans PostgreSQL

Mise en cache…!!, c'est un peu difficile d'aller en bref avec un seul article. Mais je vais essayer de partager mes connaissances apprises de Heikki / Robert Haas / Bruce Momjian bref. Dans PostgreSQL, il y a deux couches, les tampons partagés PG et le cache de la page du système d'exploitation, toute lecture/écriture doit passer par le cache du système d'exploitation (aucun contournement jusqu'à présent). Postgres écrit des données sur le cache de page du système d'exploitation et confirme à l'utilisateur qu'il a écrit sur le disque, les écritures ultérieures du cache du système d'exploitation sur le disque physique à son propre rythme. Les tampons partagés PG n'ont aucun contrôle sur le cache de page du système d'exploitation et ne savent même pas ce qu'il y a dans le cache du système d'exploitation. Ainsi, la plupart des recommandations données par Postgres DBA's/Professional's pour avoir un DISK plus rapide / un meilleur cache.

Les caches/tampons dans PostgreSQL sont plus puissants que les autres bases de données et très sophistiqués. Comme je viens d'Oracle (état d'esprit aussi… :) ), donc, ma question de qui j'ai appris était comment/quand/quoi/pourquoi etc., concernant le cache de tampon de base de données, les tampons épinglés, le cache de tampons de base de données de vidage, le préchargement de la base de données, etc., J'ai obtenu toutes mes réponses d'eux, cependant, l'approche est un peu différente. Bien que mes questions soient sur écoute, ils ont répondu avec beaucoup de patience et m'ont clarifié dans une bonne mesure le résultat que vous lisez sur ce blog…. :)..

Sur certains apprentissages (en cours d'apprentissage), j'ai dessiné un petit aperçu de la façon dont les données circulent entre la mémoire et le disque dans Postgres, ainsi que certains des outils importants et le NOUVEAU patch de Robert Haas(pg_prewarm) .

pg_buffercache
Un module contrib, qui indique ce qu'il y a dans le cache du tampon PostgreSQL. Installation ci-dessous :-

postgres=# CREATE EXTENSION pg_buffercache;

pgfincore
Il a une fonctionnalité pour donner des informations sur les données dans le cache de page du système d'exploitation. Pgfincore, le module devient très pratique lorsqu'il est associé à pg_buffercache, maintenant on peut obtenir ensemble les informations du cache de tampon PG et du cache de page du système d'exploitation. Merci à Cerdic Villemain. Pgfincore, backbone est fadvise, fincore qui sont ftools linux. Vous pouvez également utiliser fincore/fadvise en installant source. Deux choses, vous pouvez utiliser le module contrib pgfincore ou ftools, les deux résultats sont identiques. J'ai essayé les deux, ils sont tout simplement géniaux.

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
Préchargement de la relation/index dans le cache tampon PG. Est-ce possible dans PostgreSQL ? oh oui, merci à Robert Haas , qui a récemment soumis un correctif à la communauté, nous espérons qu'il sera disponible dans PG 9.2 ou PG 9.3. Cependant, vous pouvez utiliser le correctif pour vos tests sur PG 9.1.

pg_prewarm a trois MODE :

  1. PRECHARGE : Récupérer des blocs de données de manière asynchrone dans le cache du système d'exploitation uniquement et non dans les tampons PG (touche le cache du système d'exploitation uniquement)
  2. LIRE : Lit tous les blocs dans un tampon factice et les force dans le cache du système d'exploitation. (uniquement dans le cache du système d'exploitation)
  3. TAMPON : lit tous les blocs ou la plage de blocs dans le cache du tampon de la base de données.

Installation :
J'applique le patch pg_prewarm sur mon installation source PG, vous devez ajuster selon votre configuration.

  1. Décompressez l'emplacement de la source PG :/usr/local/src/postgresql-9.1.3
  2. Emplacement d'installation de la PG :/usr/local/pgsql91
  3. Tous les téléchargements Emplacement :/usr/local/src

Remarque :Installez PG avant d'appliquer le correctif pg_prewarm.

1. Téléchargez le correctif à l'emplacement /usr/local/src/
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
Patch joint E-mail :
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2. Après le téléchargement, accédez à l'emplacement de la source PG et suivez les étapes.

# 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. La commande ci-dessus créera des fichiers sous $PGPATH/contrib/extension. Vous êtes maintenant prêt à ajouter le module contrib.

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
Une combinaison de vmstat,iostat,netstat,top,etc., outil ensemble dans une seule commande linux "dstat". Lorsque la base de données se comporte de manière inhabituelle, pour en connaître la cause au niveau du système d'exploitation, nous ouvrons quelques terminaux pour extraire le processus, la mémoire, les lectures/écritures de disque, les informations réseau, ce qui est un peu pénible à mélanger entre les fenêtres. Ainsi, dstat contient plusieurs options, ce qui permet d'afficher toutes les commandes dans une seule fenêtre de sortie.

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/

Ftools Linux
Il est conçu pour fonctionner avec les appels système Linux modernes, notamment mincore, fallocate, fadvise, etc. Ftools vous aidera à déterminer quels fichiers se trouvent dans le cache du système d'exploitation. À l'aide de scripts perl/python, vous pouvez récupérer les informations du cache de page du système d'exploitation sur les fichiers objets (pg_class.relfilenode). pg_fincore est basé sur cela. Vous pouvez utiliser les scripts pgfincore ou 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.

Maintenant, nous sommes tous prêts à continuer avec l'exemple pour vérifier avec les outils et utilitaires. Dans mon exemple, j'ai une table, elle contient un index et une séquence contenant plus de 100 Mo de données.

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

Requête pour connaître la taille occupée par la table, la séquence et son index.

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)

J'ai écrit une petite requête en mêlant pgfincore et pg_buffercache pour extraire des informations du cache PG Buffer &OS Page. J'utiliserai cette requête tout au long de mon exemple, en ne collant que les résultats de cette requête.

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.

Précharger la relation/l'index avec pg_prewarm :
Avant, en faisant rebondir le cluster, j'ai lancé une requête d'analyse séquentielle de table complète sur la table "Cache", et noté le temps qui s'écoule avant de réchauffer la relation/l'index.

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)

Réchauffons la relation/index/séquence en utilisant pg_prewarm et vérifions le plan de requête.

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)

sortie 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)

Pour récupérer des informations similaires à l'aide du script python-ftools, vous devez connaître le numéro de relfilenode des objets, vérifiez ci-dessous.

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)

en utilisant le script python-ftools

N'est-ce pas intéressant….!!!!.
Maintenant, comparez le plan d'explication après avoir réchauffé la table dans le tampon.

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)

Comment vider/préchauffer la relation/l'index dans le cache du système d'exploitation ?
A l'aide de pgfadvise, vous pouvez précharger ou vider la relation du cache du système d'exploitation. Pour plus d'informations, tapez df pgfadvise* dans le terminal pour toutes les fonctions liées à pgfadvise. Vous trouverez ci-dessous un exemple de vidage du cache du système d'exploitation.

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)

Pendant que ces choses se passent dans une fenêtre, vous pouvez vérifier le rapport lecture/écriture en utilisant dstat. Pour plus d'options, utilisez dstat –list
dstat -s –top-io –top-bio –top-mem

Plage de préchargement des blocs à l'aide de la fonctionnalité de plage pg_prewarm.
Supposons que, pour une raison quelconque, vous souhaitiez faire rebondir le cluster, mais qu'une des grandes tables qui se trouve dans le tampon fonctionne bien. Lors du rebond, votre table n'est plus dans les tampons, pour revenir à l'état d'origine tel qu'il était avant le rebond, vous devez savoir combien de blocs de table se trouvaient dans les tampons et les précharger à l'aide de l'option pg_prewarm range.

J'ai créé une table en interrogeant pg_buffercache et plus tard j'ai envoyé des informations sur la plage de blocs à pg_prewarm. De ce fait, les tampons partagés sont de retour avec la table précédemment chargée. Voir l'exemple.

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

Faites rebondir le cluster et préchargez la plage de blocs liés à la table dans des tampons à partir de "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)

Voyez, mon shared_buffer est de retour en jeu.

Profitez…!!! sera de retour avec des choses plus intéressantes. Postez vos commentaires.