sql >> Database >  >> RDS >> PostgreSQL

Caching in PostgreSQL

Caching...!!, het is een beetje moeilijk om kort te gaan met een enkel artikel. Maar zal proberen mijn kennis te delen die ik heb geleerd van Heikki / Robert Haas / Bruce Momjian in het kort. In PostgreSQL zijn er twee lagen, gedeelde PG-buffers en OS Page-cache, elk lezen/schrijven zou door de OS-cache moeten gaan (tot nu toe niet omzeild). Postgres schrijft gegevens naar de OS-paginacache en bevestigt aan de gebruiker dat het naar de schijf is geschreven, later schrijft de OS-cache naar de fysieke schijf in zijn eigen tempo. Gedeelde PG-buffers hebben geen controle over OS Page Cache en weten niet eens wat zich in de OS-cache bevindt. Dus de meeste aanbevelingen van Postgres DBA's/Professional's om een ​​snellere SCHIJF / betere cache te hebben.

Caches/buffers in PostgreSQL zijn sterker dan andere databases en zeer geavanceerd. Ik heb een Oracle-achtergrond (mindset ook ... :)), dus mijn vraag van wie ik heb geleerd was hoe / wanneer / wat / waarom enz., Met betrekking tot databasebuffercache, vastgezette buffers, Flushing databasebuffercache, voorladen van database enz., Ik heb al mijn antwoorden van hen gekregen, maar de aanpak is iets anders. Hoewel mijn vragen lastig waren, hebben ze met veel geduld geantwoord en me in goede mate verduidelijkt, met als resultaat dat je deze blog leest .... :)..

Op sommige lessen (nog steeds aan het leren), heb ik een klein overzicht gemaakt van hoe gegevens stromen tussen geheugen naar schijf in Postgres en ook enkele van de belangrijke hulpmiddelen en NIEUWE patch door Robert Haas(pg_prewarm) .

pg_buffercache
Een contrib-module, die vertelt wat er in de PostgreSQL-buffercache zit. Installatie hieronder:-

postgres=# CREATE EXTENSION pg_buffercache;

pgfincore
Het heeft een functionaliteit om informatie te geven over welke gegevens in OS Page Cache. Pgfincore, module wordt erg handig wanneer het wordt geknuppeld met pg_buffercache, nu kan men PG-buffercache &OS Page Cache-informatie samen krijgen. Met dank aan Cerdic Villemain. Pgfincore, backbone is fadvise, fincore die linux-tools zijn. U kunt fincore/fadvise ook gebruiken door source te installeren. Twee dingen, je kunt de pgfincore contrib-module of ftools gebruiken, beide resulteren hetzelfde. Ik heb ze allebei geprobeerd, ze zijn gewoon geweldig.

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
Vooraf laden van de relatie/index in de PG-buffercache. Is het mogelijk in PostgreSQL? oh ja, met dank aan Robert Haas , die onlangs een patch naar de community heeft gestuurd, hopelijk is deze beschikbaar in PG 9.2 of PG 9.3. U kunt de patch echter gebruiken voor uw tests op PG 9.1.

pg_prewarm heeft drie MODUS:

  1. PREFETCH: Gegevensblokken asynchroon ophalen in OS-cache, alleen niet in PG-buffers (alleen OS-cache)
  2. LEES: Leest alle blokken in de dummy-buffer en forceert de OS-cache. (alleen voor OS-cache)
  3. BUFFER: leest alle blokken of het bereik van blokken in de buffercache van de database.

Installatie:
Ik pas de pg_prewarm-patch toe op mijn PG-broninstallatie, u moet deze aanpassen volgens uw instellingen.

  1. Locatie van PG-bron verwijderen:/usr/local/src/postgresql-9.1.3
  2. PG-installatielocatie:/usr/local/pgsql91
  3. Alle downloads Locatie:/usr/local/src

Opmerking:installeer PG voordat u pg_prewarm patch toepast.

1. Download de patch naar /usr/local/src/ location
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
Bijgevoegde e-mail van de patch:
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2. Ga na het downloaden naar de PG-bronlocatie en volg de stappen.

# 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. Bovenstaande opdracht maakt bestanden aan onder $PGPATH/contrib/extension. Nu ben je klaar om de bijdragemodule toe te voegen.

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
Een combinatie van vmstat,iostat,netstat,top,etc., tools samen in één "dstat" linux-commando. Wanneer de database zich ongewoon gedraagt, om de oorzaak op OS-niveau te weten, openen we een paar terminals om processen, geheugen, schijflezen/schrijven, netwerkinformatie te trekken, wat een beetje lastig is om tussen vensters te schuiven. Dus, dstat heeft verschillende opties erin, wat helpt om alle commando's in één uitvoer één venster te tonen.

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
Het is ontworpen voor het werken met moderne linux-systeemaanroepen, waaronder mincore, fallocate, fadvise, enz. Ftools helpt je om erachter te komen welke bestanden zich in de OS-cache bevinden. Met behulp van perl/python-scripts kunt u de cache-informatie van de OS-pagina over objectbestanden (pg_class.relfilenode) ophalen. pg_fincore is hierop gebaseerd. U kunt pgfincore- of ftools-scripts gebruiken.

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.

Nu zijn we helemaal klaar om verder te gaan met het voorbeeld om te controleren met de tools en hulpprogramma's. In mijn voorbeeld heb ik een tabel, deze heeft één index en reeks met 100+ MB aan gegevens erin.

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

Vraag om de grootte te kennen die wordt ingenomen door tabel, reeks en zijn 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)

Ik heb een kleine vraag geschreven door pgfincore en pg_buffercache te gebruiken om informatie uit de PG Buffer &OS Page-cache te halen. Ik zal deze query in mijn hele voorbeeld gebruiken en alleen de uitvoer van deze query plakken.

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.

Vooraf laden van relatie/index met pg_prewarm:
Voordat ik het cluster liet stuiteren, heb ik een sequentiële scanquery voor de volledige tabel uitgevoerd op de "Cache"-tabel en de tijd genoteerd die is voordat de relatie/index wordt opgewarmd.

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)

Laat een warme relatie/index/reeks gebruiken met pg_prewarm en controleer het queryplan.

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-uitvoer:

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)

Om vergelijkbare informatie op te halen met behulp van het python-ftools-script moet je het relfilenode-nummer van het object weten, kijk hieronder.

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)

python-ftools-script gebruiken

Is het niet interessant….!!!!.
Vergelijk nu het uitlegplan na de opwarmtafel in 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)

Hoe de relatie/index in OS-cache doorspoelen/voorverwarmen?
Met pgfadvise kunt u de relatie vooraf laden of wissen uit de OS-cache. Typ voor meer informatie df pgfadvise* in terminal voor alle functies die verband houden met pgfadvise. Hieronder ziet u een voorbeeld van het leegmaken van de OS-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)

Terwijl deze dingen in één venster plaatsvinden, kunt u de lees-/schrijfverhouding controleren met behulp van dstat. Gebruik voor meer opties dstat –list
dstat -s –top-io –top-bio –top-mem

Bereik van blokken vooraf laden met behulp van pg_prewarm bereikfunctionaliteit.
Veronderstel dat u om de een of andere reden het cluster wilt bouncen, maar dat een van de grote tabellen in de buffer goed presteert. Bij het stuiteren zit je tafel niet meer in buffers, om terug te keren naar de oorspronkelijke staat zoals het was voordat het stuiterde, moet je weten hoeveel tafelblokken er in buffers waren en ze vooraf laden met de pg_prewarm bereikoptie.

Ik heb een tabel gemaakt door pg_buffercache op te vragen en later heb ik informatie over het blokbereik naar pg_prewarm gestuurd. Hierdoor zijn gedeelde buffers terug met de eerder geladen tabel erin. Zie het voorbeeld.

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

Bounce het cluster en laad het bereik van blokken gerelateerd aan de tabel vooraf in buffers van 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)

Kijk, mijn shared_buffer's zijn weer in het spel.

Genieten van…!!! zal terugkomen met meer interessante dingen. Plaats uw opmerkingen.


  1. SQLite GLOB

  2. Hoe u uw MySQL- en MariaDB-database kunt beschermen tegen cyberaanvallen op een openbaar netwerk

  3. Installeer SQL Server 2019 op een Mac

  4. Hoe u met sqlalchemy dynamisch kunt binden aan de database-engine per verzoek