PostgreSQLのキャッシュ/バッファは、他のデータベースと同様に強力で、高度に洗練されています。オラクルのバックグラウンド(マインドセットも…:))からのように、データベースバッファキャッシュ、固定バッファ、データベースバッファキャッシュのフラッシュ、データベースのプリロードなどに関して、どのように、いつ、何を、なぜかなどを学びました。私は彼らからすべての答えを得ました、しかし、アプローチは少し異なります。私の質問はバグだらけでしたが、彼らは非常に忍耐強く答え、私をかなり明確にしてくれたので、結果としてあなたはこのブログを読んでいます…。 :) ..
いくつかの学習(まだ学習中)について、Postgresのメモリからディスクへのデータフローと、 Robert Haas(pg_prewarm)によるいくつかの重要なツールと新しいパッチの概要を描きました。 。
pg_buffercache
PostgreSQLバッファキャッシュの内容を通知するcontribモジュール。以下のインストール:-
postgres=# CREATE EXTENSION pg_buffercache;
pgfincore
OSページキャッシュ内のデータに関する情報を提供する機能があります。 Pgfincore、モジュールはpg_buffercacheと組み合わせて使用すると非常に便利になり、PGバッファキャッシュとOSページキャッシュの情報を一緒に取得できるようになりました。 CerdicVillemainに感謝します。 Pgfincore、バックボーンはfadvise、fincoreはLinuxftoolsです。 sourceをインストールしてfincore/fadviseを使用することもできます。 2つは、pgfincorecontribモジュールまたはftoolsを使用して両方の結果が同じになることです。私は両方を試しました、彼らは単に素晴らしいです。
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
リレーション/インデックスをPGバッファキャッシュにプリロードします。 PostgreSQLで可能ですか?はい、 Robert Haasに感謝します 、最近コミュニティにパッチを提出した人は、PG9.2またはPG9.3で利用できるようになることを願っています。ただし、PG9.1でのテストにパッチを使用できます。
pg_prewarmには3つのモードがあります:
- プリフェッチ: データブロックを非同期でOSキャッシュにフェッチし、PGバッファにはフェッチしません(OSキャッシュのみにヒットします)
- 読む: すべてのブロックをダミーバッファに読み込み、OSキャッシュに強制します。 (OSキャッシュのみにヒットします)
- バッファ: すべてのブロックまたはブロックの範囲をデータベースバッファキャッシュに読み込みます。
インストール:
PGソースインストールにpg_prewarmパッチを適用しています。セットアップに従って、微調整する必要があります。
- PGソースのUntarロケーション:/usr/local/src/postgresql-9.1.3
- PGインストール場所:/ usr / local / pgsql91
- すべてのダウンロード場所:/ usr / local / src
注:pg_prewarmパッチを適用する前にPGをインストールしてください。
1.パッチを/usr/ local /src/の場所にダウンロードします
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
添付メールのパッチ:
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2。ダウンロード後、PGソースの場所に移動し、手順に従います。
# 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.上記のコマンドは、$ PGPATH / contrib/extensionの下にファイルを作成します。これで、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
vmstat、iostat、netstat、topなどのツールを1つの「dstat」Linuxコマンドに組み合わせたもの。データベースが異常に動作する場合、OSレベルから原因を知るために、いくつかの端末を開いて、プロセス、メモリ、ディスクの読み取り/書き込み、ネットワーク情報をプルします。これは、ウィンドウ間でシャッフルするのに少し苦労します。そのため、dstatにはサーバーオプションがあり、すべてのコマンドを1つの出力1つのウィンドウに表示するのに役立ちます。
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 ftools
mincore、fallocate、fadviseなどの最新のLinuxシステムコールで動作するように設計されています。Ftoolsは、OSキャッシュにあるファイルを把握するのに役立ちます。 perl / pythonスクリプトを使用すると、オブジェクトファイル(pg_class.relfilenode)のOSページキャッシュ情報を取得できます。 pg_fincoreはこれに基づいています。 pgfincoreまたは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.
これで、ツールとユーティリティを確認するための例に進む準備が整いました。私の例では、テーブルがあり、100MB以上のデータを含む1つのインデックスとシーケンスがあります。
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
テーブル、シーケンス、およびそのインデックスが占めるサイズを知るためにクエリを実行します。
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)
pgfincoreとpg_buffercacheをクラブして、PGバッファーとOSページのキャッシュから情報を取得することで小さなクエリを作成しました。このクエリの出力のみを貼り付けて、例全体でこのクエリを使用します。
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.
pg_prewarmを使用したリレーション/インデックスのプリロード:
クラスターをバウンスする前に、「キャッシュ」テーブルに対してフルテーブルシーケンシャルスキャンクエリを実行し、リレーション/インデックスをウォームアップする前の時間を記録しました。
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)
pg_prewarmを使用してリレーション/インデックス/シーケンスをウォームし、クエリプランを確認します。
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出力:
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)
python-ftoolsスクリプトを使用して同様の情報を取得するには、オブジェクトのrelfilenode番号を知る必要があります。以下を確認してください。
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スクリプトを使用する
面白くないですか…。!!!!。
テーブルをバッファに温めた後、説明プランを比較してください。
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)
OSキャッシュのリレーション/インデックスをフラッシュ/プリウォームする方法は?
pgfadviseを使用すると、OSキャッシュからリレーションをプリロードまたはフラッシュできます。詳細については、pgfadviseに関連するすべての機能について、ターミナルにdfpgfadvise*と入力してください。以下は、OSキャッシュをフラッシュする例です。
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)
これらのことが1つのウィンドウで行われている間、dstatを使用して読み取り/書き込み比率を確認できます。その他のオプションについては、dstat –list
dstat -s –top-io –top-bio –top-mem
pg_prewarm範囲機能を使用してブロックの範囲をプリロードします。
何らかの理由でクラスターをバウンスしたいが、バッファー内にある大きなテーブルの1つが正常に機能していると仮定します。バウンス時に、テーブルがバッファに存在しなくなり、バウンス前の元の状態に戻るには、バッファに存在するテーブルブロックの数を確認し、pg_prewarmrangeオプションを使用してそれらをプリロードする必要があります。
pg_buffercacheを照会してテーブルを作成し、後でブロック範囲情報をpg_prewarmに送信しました。これにより、共有バッファは以前にロードされたテーブルに戻ります。例を参照してください。
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
クラスタをバウンスし、テーブルに関連するブロックの範囲を「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)
ほら、私のshared_bufferが復活しました。
楽しみ…!!!もっと面白いもので戻ってきます。コメントを投稿してください。