БУФЕРНЫЙ КЭШ ~~~~~~~~~~~~ Создадим отдельную базу данных: => create database db7; CREATE DATABASE => \c db7 You are now connected to database "db7" as user "postgres". И таблицу в ней: => create table test(t text) with (autovacuum_enabled=off); CREATE TABLE => insert into test select 'line '||s.id from generate_series(1,500) as s(id); INSERT 0 500 => vacuum analyze test; VACUUM ....................................................................... Уменьшим временно размер буферного кэша, чтобы упростить наблюдение за ним. => alter system set shared_buffers=512; ALTER SYSTEM => \q pg_ctl restart -w -m fast -l /home/postgres/logfile waiting for server to shut down.... done server stopped waiting for server to start.... done server started ....................................................................... Проверим размер кэша: psql => \c db7 You are now connected to database "db7" as user "postgres". => select setting, unit from pg_settings where name = 'shared_buffers'; setting | unit ---------+------ 512 | 8kB (1 row) ....................................................................... Содержимое буферного кэша можно посмотреть с помощью расширения: => create extension pg_buffercache; CREATE EXTENSION ....................................................................... Создадим для удобства представление: => create view pg_buffercache_v as => select bufferid, => (select c.relname => from pg_class c => where pg_relation_filenode(c.oid) = b.relfilenode => ) relname, => case relforknumber => when 0 then 'main' => when 1 then 'fsm' => when 2 then 'vm' => end relfork, => relblocknumber, => isdirty, => usagecount => from pg_buffercache b => where b.reldatabase in (0,(select oid from pg_database where datname=current_database())) => and b.usagecount is not null; CREATE VIEW Условие на базу данных необходимо, так как в буферном кэше содержатся данные всего кластера. Расшифровать мы можем только информацию из той БД, к которой подключены. Глобальные объекты считаются принадлежащими БД с нулевым oid. ....................................................................... => select * from pg_buffercache_v limit 20; bufferid | relname | relfork | relblocknumber | isdirty | usagecount ----------+-----------------------------------------+---------+----------------+---------+------------ 1 | pg_database | main | 0 | f | 5 2 | pg_authid | main | 0 | f | 5 55 | pg_database_oid_index | main | 0 | f | 3 56 | pg_database_oid_index | main | 1 | f | 3 57 | pg_db_role_setting_databaseid_rol_index | main | 0 | f | 5 58 | pg_authid_rolname_index | main | 0 | f | 2 59 | pg_authid_rolname_index | main | 1 | f | 2 60 | pg_authid_oid_index | main | 0 | f | 2 61 | pg_authid_oid_index | main | 1 | f | 2 62 | pg_database_datname_index | main | 0 | f | 2 63 | pg_database_datname_index | main | 1 | f | 4 64 | pg_class | main | 0 | t | 5 65 | pg_class | main | 1 | f | 5 66 | pg_class | main | 2 | f | 5 67 | pg_attribute | main | 0 | f | 5 68 | pg_attribute | main | 1 | f | 5 69 | pg_attribute | main | 2 | f | 5 70 | pg_attribute | main | 3 | f | 5 71 | pg_attribute | main | 4 | f | 5 72 | pg_attribute | main | 5 | f | 5 (20 rows) ....................................................................... Используя это расширение, можно наблюдать за состоянием кэша с разных сторон. Кроме информации о том, как представлена в кэше та или иная страница, можно, например, посмотреть распределение буферов по их "популярности": => select usagecount, => count(*) => from pg_buffercache => group by usagecount => order by usagecount; usagecount | count ------------+------- 1 | 95 2 | 42 3 | 8 4 | 15 5 | 140 | 212 (6 rows) ....................................................................... Посмотрим на расширение для прогрева кэша: => create extension pg_prewarm; CREATE EXTENSION ....................................................................... Например, сейчас в кэше нет таблицы test (мы перезагружали сервер): => select * from pg_buffercache_v where relname = 'test'; bufferid | relname | relfork | relblocknumber | isdirty | usagecount ----------+---------+---------+----------------+---------+------------ (0 rows) ....................................................................... В простейшем виде указанная таблица считывается в буферный кэш. => select pg_prewarm('test'); pg_prewarm ------------ 3 (1 row) => select * from pg_buffercache_v where relname = 'test'; bufferid | relname | relfork | relblocknumber | isdirty | usagecount ----------+---------+---------+----------------+---------+------------ 304 | test | main | 0 | f | 1 305 | test | main | 1 | f | 1 306 | test | main | 2 | f | 1 (3 rows) Расширение pg_prewarm может также использоваться для прогрева кэша операционной системы. ....................................................................... Изменим одну строку таблицы (происходит удаление и вставка): => update test set t = 'changed' where t = 'line 1'; UPDATE 1 => select * from pg_buffercache_v where relname = 'test'; bufferid | relname | relfork | relblocknumber | isdirty | usagecount ----------+---------+---------+----------------+---------+------------ 304 | test | main | 0 | t | 2 305 | test | main | 1 | f | 2 306 | test | main | 2 | t | 3 308 | test | vm | 0 | t | 1 309 | test | fsm | 0 | f | 1 310 | test | fsm | 1 | f | 1 311 | test | fsm | 2 | f | 1 (7 rows) ....................................................................... Следует учитывать, что расширение pg_buffercache накладывает блокировки на время доступа к кэшу, поэтому не следует использовать его слишком часто на продуктивной среде. ....................................................................... ПРОЦЕСС ФОНОВОЙ ЗАПИСИ ~~~~~~~~~~~~~~~~~~~~~~ Работа фонового процесса записи отражается в собираемой статистике; за ней можно наблюдать с помощью представления pg_stat_bgwriter. Часть полей этого представления относится и к процессу checkpointer. Пока мы не будем обращать на них внимание. => select buffers_clean, maxwritten_clean, buffers_backend from pg_stat_bgwriter; buffers_clean | maxwritten_clean | buffers_backend ---------------+------------------+----------------- 0 | 0 | 71 (1 row) * buffers_clean - количество буферов, записанных на диск процессом writer, * maxwritten_clean - количество остановок по достижению bgwriter_lru_maxpages, * buffers_backend - количество буферов, записанных серверными процессами. ....................................................................... Дадим нагрузку на базу данных. Для этого удобно воспользоваться расширением pgbench. Оно позволяет прогонять тест TPC-B или любой пользовательский сценарий. Сначала надо создать таблицы для теста: pgbench -i db7 NOTICE: table "pgbench_history" does not exist, skipping NOTICE: table "pgbench_tellers" does not exist, skipping NOTICE: table "pgbench_accounts" does not exist, skipping NOTICE: table "pgbench_branches" does not exist, skipping creating tables... 100000 of 100000 tuples (100%) done (elapsed 0.12 s, remaining 0.00 s) vacuum... set primary keys... done. ....................................................................... Для чистоты эксперимента выполним контрольную точку, чтобы сбросить все грязные буферы на диск, и сбросим статистику. => checkpoint; CHECKPOINT => select pg_stat_reset_shared('bgwriter'); pg_stat_reset_shared ---------------------- (1 row) ....................................................................... Теперь можно запускать сам тест. Установим длительность 30 секунд и скорость 100 транзакций в секунду. pgbench -T 30 -R 100 -P 1 db7 starting vacuum...end. progress: 1.0 s, 102.0 tps, lat 2.523 ms stddev 0.977, lag 0.608 ms progress: 2.0 s, 99.0 tps, lat 3.867 ms stddev 5.540, lag 1.495 ms progress: 3.0 s, 98.0 tps, lat 2.379 ms stddev 0.821, lag 0.413 ms progress: 4.0 s, 103.0 tps, lat 2.393 ms stddev 1.207, lag 0.506 ms progress: 5.0 s, 108.0 tps, lat 2.458 ms stddev 0.847, lag 0.558 ms progress: 6.0 s, 91.0 tps, lat 2.229 ms stddev 0.482, lag 0.359 ms progress: 7.0 s, 88.0 tps, lat 2.649 ms stddev 3.175, lag 0.510 ms progress: 8.0 s, 91.0 tps, lat 2.331 ms stddev 1.031, lag 0.511 ms progress: 9.0 s, 88.0 tps, lat 2.395 ms stddev 0.871, lag 0.502 ms progress: 10.0 s, 91.0 tps, lat 2.358 ms stddev 0.804, lag 0.388 ms progress: 11.0 s, 100.0 tps, lat 2.304 ms stddev 0.568, lag 0.444 ms progress: 12.0 s, 98.0 tps, lat 2.412 ms stddev 1.891, lag 0.437 ms progress: 13.0 s, 94.0 tps, lat 2.187 ms stddev 0.502, lag 0.303 ms progress: 14.0 s, 105.0 tps, lat 3.594 ms stddev 5.307, lag 1.482 ms progress: 15.0 s, 114.0 tps, lat 2.158 ms stddev 0.452, lag 0.318 ms progress: 16.0 s, 97.0 tps, lat 2.251 ms stddev 0.572, lag 0.397 ms progress: 17.0 s, 80.0 tps, lat 2.761 ms stddev 2.148, lag 0.537 ms progress: 18.0 s, 110.0 tps, lat 2.119 ms stddev 0.475, lag 0.340 ms progress: 19.0 s, 103.0 tps, lat 2.273 ms stddev 0.731, lag 0.436 ms progress: 20.0 s, 99.0 tps, lat 2.277 ms stddev 0.783, lag 0.483 ms progress: 21.0 s, 93.0 tps, lat 2.237 ms stddev 0.667, lag 0.430 ms progress: 22.0 s, 94.0 tps, lat 2.559 ms stddev 1.519, lag 0.499 ms progress: 23.0 s, 105.0 tps, lat 2.113 ms stddev 0.679, lag 0.356 ms progress: 24.0 s, 106.0 tps, lat 4.159 ms stddev 9.069, lag 1.868 ms progress: 25.0 s, 85.0 tps, lat 2.266 ms stddev 0.606, lag 0.373 ms progress: 26.0 s, 97.0 tps, lat 2.348 ms stddev 1.151, lag 0.554 ms progress: 27.0 s, 88.0 tps, lat 2.393 ms stddev 2.446, lag 0.330 ms progress: 28.0 s, 104.0 tps, lat 2.189 ms stddev 0.625, lag 0.411 ms progress: 29.0 s, 87.0 tps, lat 2.283 ms stddev 0.762, lag 0.373 ms progress: 30.0 s, 93.0 tps, lat 2.286 ms stddev 0.626, lag 0.476 ms transaction type: TPC-B (sort of) scaling factor: 1 query mode: simple number of clients: 1 number of threads: 1 duration: 30 s number of transactions actually processed: 2912 latency average: 2.496 ms latency stddev: 2.558 ms rate limit schedule lag: avg 0.564 (max 52.842) ms tps = 97.064247 (including connections establishing) tps = 97.070999 (excluding connections establishing) ....................................................................... => select buffers_clean, maxwritten_clean, buffers_backend from pg_stat_bgwriter; buffers_clean | maxwritten_clean | buffers_backend ---------------+------------------+----------------- 3037 | 7 | 168 (1 row) По полученной информации видно, что основную работу выполнял процесс writer, хотя и серверным процессам пришлось немного поработать. ....................................................................... Конец демонстрации. ....................................................................... => alter system reset all; ALTER SYSTEM => \q pg_ctl restart -w -m fast -l /home/postgres/logfile waiting for server to shut down.... done server stopped waiting for server to start.... done server started