PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Zwischenspeichern in PostgreSQL

Caching…!!, es ist ein bisschen schwer, es mit einzelnen Artikeln kurz zu machen. Aber ich werde versuchen, mein Wissen von Heikki / Robert Haas / Bruce Momjian zu teilen Zusamenfassend. In PostgreSQL gibt es zwei Schichten, gemeinsam genutzte PG-Puffer und OS-Seitencache, alle Lese-/Schreibvorgänge sollten den OS-Cache durchlaufen (bis jetzt keine Umgehung). Postgres schreibt Daten in den OS Page Cache und bestätigt dem Benutzer, wie es auf die Festplatte geschrieben wurde, später schreibt der OS Cache in seinem eigenen Tempo auf die physische Festplatte. PG Shared Buffers haben keine Kontrolle über den OS Page Cache und wissen nicht einmal, was sich im OS Cache befindet. Die meisten Empfehlungen von Postgres-DBAs/-Profis sind also, schnellere DISK/besseren Cache zu haben.

Caches/Puffer in PostgreSQL sind stärker als andere Datenbanken und hochentwickelt. Da ich aus dem Oracle-Hintergrund komme (Denkweise auch ... :)), war meine Frage, von wem ich gelernt habe, wie / wann / was / warum usw. in Bezug auf den Datenbankpuffer-Cache, gepinnte Puffer, das Leeren des Datenbankpuffer-Cache, das Vorladen der Datenbank usw. Ich habe alle meine Antworten von ihnen bekommen, aber der Ansatz ist etwas anders. Obwohl meine Fragen lästig waren, beantworteten sie sie mit großer Geduld und klärten mich zu einem guten Teil auf, was dazu führte, dass Sie diesen Blog lesen…. :)..

Bei einigen Erkenntnissen (die noch zu lernen sind) habe ich einen kleinen Überblick darüber gezeichnet, wie Daten zwischen Speicher und Festplatte in Postgres fließen, sowie einige der wichtigen Tools und den NEUEN Patch von Robert Haas(pg_prewarm) .

pg_buffercache
Ein Contrib-Modul, das mitteilt, was sich im PostgreSQL-Puffercache befindet. Installation unten:-

postgres=# CREATE EXTENSION pg_buffercache;

pgfincore
Es hat eine Funktion, um Informationen darüber zu geben, welche Daten sich im OS Page Cache befinden. Pgfincore, Modul wird sehr praktisch, wenn es mit pg_buffercache kombiniert wird, jetzt kann man PG Buffer Cache &OS Page Cache Informationen zusammen bekommen. Danke an Cerdic Villemain. Pgfincore, Backbone ist Fadvise, Fincore, das sind Linux-Tools. Sie können fincore/fadvise auch verwenden, indem Sie den Quellcode installieren. Zwei Dinge, Sie können das pgfincore Contrib-Modul oder ftools verwenden, die beide dasselbe Ergebnis haben. Ich habe beide ausprobiert, sie sind einfach genial.

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
Vorabladen der Relation/des Index in den PG-Puffercache. Ist es in PostgreSQL möglich? ach ja, danke an Robert Haas , der kürzlich einen Patch an die Community übermittelt hat, hoffentlich ist er in PG 9.2 oder PG 9.3 verfügbar. Sie können den Patch jedoch zum Testen auf PG 9.1 verwenden.

pg_prewarm hat drei MODEs:

  1. PRÄFUCH: Datenblöcke asynchron nur in den OS-Cache holen, nicht in PG-Puffer (trifft nur auf den OS-Cache)
  2. LESEN: Liest alle Blöcke in den Dummy-Puffer und zwingt sie in den OS-Cache. (trifft nur auf den OS-Cache)
  3. PUFFER: liest alle Blöcke oder Blockbereiche in den Datenbankpuffer-Cache.

Installation:
Ich wende den pg_prewarm-Patch auf meine PG-Quellinstallation an, Sie müssen gemäß Ihrem Setup optimieren.

  1. Untar-Standort der PG-Quelle:/usr/local/src/postgresql-9.1.3
  2. PG-Installationsort:/usr/local/pgsql91
  3. Speicherort aller Downloads:/usr/local/src

Hinweis:Installieren Sie PG, bevor Sie den Patch pg_prewarm anwenden.

1. Laden Sie den Patch unter /usr/local/src/ location herunter
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
Patch angehängte E-Mail:
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2. Gehen Sie nach dem Download zum Speicherort der PG-Quelle und folgen Sie den Schritten.

# 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. Der obige Befehl erstellt Dateien unter $PGPATH/contrib/extension. Jetzt können Sie das Contrib-Modul hinzufügen.

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
Eine Kombination aus vmstat,iostat,netstat,top usw., Tool zusammen in einem „dstat“-Linux-Befehl. Wenn sich die Datenbank ungewöhnlich verhält, öffnen wir einige Terminals, um die Ursache auf Betriebssystemebene zu ermitteln, um Prozesse, Speicher, Festplatten-Lese-/Schreibvorgänge und Netzwerkinformationen abzurufen, was ein wenig mühsam ist, zwischen den Fenstern zu wechseln. dstat hat also mehrere Optionen, die dabei helfen, alle Befehle in einer Ausgabe in einem Fenster anzuzeigen.

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/

Linux-Tools
Es wurde für die Arbeit mit modernen Linux-Systemaufrufen entwickelt, einschließlich Mincore, Fallocate, Fadvise usw. Ftools hilft Ihnen herauszufinden, welche Dateien sich im Betriebssystem-Cache befinden. Mithilfe von Perl/Python-Skripten können Sie OS-Seiten-Cache-Informationen zu Objektdateien (pg_class.relfilenode) abrufen. pg_fincore baut darauf auf. Sie können pgfincore- oder ftools-Skripte verwenden.

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.

Jetzt sind wir bereit, mit dem Beispiel fortzufahren, um die Tools und Dienstprogramme zu überprüfen. In meinem Beispiel habe ich eine Tabelle mit einem Index und einer Sequenz mit mehr als 100 MB Daten.

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

Abfrage, um die von Tabelle, Sequenz und ihrem Index belegte Größe zu erfahren.

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)

Ich habe eine kleine Abfrage geschrieben, indem ich pgfincore und pg_buffercache vereinige, um Informationen aus dem Cache von PG Buffer &OS Page zu ziehen. Ich werde diese Abfrage in meinem gesamten Beispiel verwenden und nur die Ausgaben dieser Abfrage einfügen.

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.

Beziehung/Index vorab laden mit pg_prewarm:
Vor dem Bouncen des Clusters habe ich eine sequenzielle Scan-Abfrage der gesamten Tabelle auf die „Cache“-Tabelle ausgelöst und die Zeit notiert, die vor dem Aufwärmen der Relation/des Index liegt.

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)

Lassen Sie Relation/Index/Sequenz mit pg_prewarm warm und überprüfen Sie den Abfrageplan.

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)

pgfincore-Ausgabe:

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)

Um ähnliche Informationen mit dem Skript python-ftools abzurufen, müssen Sie die Objektrelfilenode-Nummer kennen, siehe unten.

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)

Verwenden des python-ftools-Skripts

Ist es nicht interessant….!!!!.
Vergleichen Sie jetzt den Erklärungsplan nach dem Aufwärmen der Tabelle in den Puffer.

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)

Wie wird die Relation/der Index im OS-Cache geleert/vorgewärmt?
Mit pgfadvise können Sie die Relation vorab laden oder aus dem OS-Cache löschen. Geben Sie für weitere Informationen im Terminal df pgfadvise* für alle Funktionen ein, die sich auf pgfadvise beziehen. Unten sehen Sie ein Beispiel für das Leeren des Betriebssystem-Cache.

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)

Während diese Dinge in einem Fenster ablaufen, können Sie das Lese-/Schreibverhältnis mit dstat überprüfen. Für weitere Optionen verwenden Sie dstat –list
dstat -s –top-io –top-bio –top-mem

Vorladen des Bereichs von Blöcken mit pg_prewarm-Bereichsfunktionalität.
Angenommen, Sie möchten den Cluster aus irgendeinem Grund zurückprallen lassen, aber eine große Tabelle, die sich im Puffer befindet, funktioniert gut. Beim Bouncing befindet sich Ihre Tabelle nicht mehr in den Puffern. Um zum ursprünglichen Zustand vor dem Bouncing zurückzukehren, müssen Sie wissen, wie viele Tabellenblöcke in den Puffern waren, und sie mit der pg_prewarm-Bereichsoption vorladen.

Ich habe eine Tabelle erstellt, indem ich pg_buffercache abgefragt habe, und später habe ich Blockbereichsinformationen an pg_prewarm gesendet. Dadurch sind gemeinsam genutzte Puffer mit der zuvor geladenen Tabelle wieder da. Siehe Beispiel.

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

Bouncen Sie den Cluster und laden Sie den Bereich der Blöcke, die sich auf die Tabelle beziehen, vorab in Puffer aus „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)

Sehen Sie, mein shared_buffer ist wieder im Spiel.

Genießen…!!! wird mit interessanteren Sachen zurück sein. Posten Sie Ihre Kommentare.