Контрольная точка

Заглянем в управляющий файл /usr/local/pgsql/data/global/pg_control. Это можно сделать с помощью утилиты pg_controldata.

postgres$ pg_controldata
pg_control version number:            1002
Catalog version number:               201707211
Database system identifier:           6724283719152707292
Database cluster state:               in production
pg_control last modified:             Пн 12 авг 2019 17:15:45
Latest checkpoint location:           0/1BF5734
Prior checkpoint location:            0/1BF5668
Latest checkpoint's REDO location:    0/1BF56FC
Latest checkpoint's REDO WAL file:    000000010000000000000001
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0:667
Latest checkpoint's NextOID:          24817
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        548
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  666
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Пн 12 авг 2019 17:15:45
Fake LSN counter for unlogged rels:   0/1
Minimum recovery ending location:     0/0
Min recovery ending loc's timeline:   0
Backup start location:                0/0
Backup end location:                  0/0
End-of-backup record required:        no
wal_level setting:                    replica
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off
Maximum data alignment:               4
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        2000
Size of a large-object chunk:         2048
Date/time type storage:               64-bit integers
Float4 argument passing:              by value
Float8 argument passing:              by reference
Data page checksum version:           1
Mock authentication nonce:            f6a300dfc223e2b1ea9239f32ab1de58482237576b9bdb4e17a53f779a59dc9e

Видим много справочной информации, из которой особый интерес представляют данные о последней контрольной точке и статус кластера: "in production".


Выполним вручную контрольную точку и посмотрим, как это отражается в журнале и в управляющем файле.

=> SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn 
---------------------------
 0/1C34A54
(1 row)

=> SELECT pg_walfile_name('0/1C34A54');
     pg_walfile_name      
--------------------------
 000000010000000000000001
(1 row)

=> CHECKPOINT;
CHECKPOINT
=> SELECT pg_current_wal_insert_lsn();
 pg_current_wal_insert_lsn 
---------------------------
 0/1C34AF0
(1 row)


В журнал попадает запись о том, что контрольная точка пройдена:

postgres$ pg_waldump -p /usr/local/pgsql/data/pg_wal -s 0/1C34A54 -e 0/1C34AF0 000000010000000000000001
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/01C34A54, prev 0/01C34A30, desc: RUNNING_XACTS nextXid 671 latestCompletedXid 670 oldestRunningXid 671
rmgr: XLOG        len (rec/tot):    102/   102, tx:          0, lsn: 0/01C34A88, prev 0/01C34A54, desc: CHECKPOINT_ONLINE redo 0/1C34A54; tli 1; prev tli 1; fpw true; xid 0:671; oid 24817; multi 1; offset 0; oldest xid 548 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 671; online

В описании записи указан LSN начала контрольной точки (redo).


Сравним с данными управляющего файла:

postgres$ pg_controldata | egrep 'Latest.*location'
Latest checkpoint location:           0/1C34A88
Latest checkpoint's REDO location:    0/1C34A54

Данные о LSN, очевидно, совпадают.


Восстановление

Теперь сымитируем сбой, принудительно выключив сервер.

=> CREATE DATABASE wal_checkpoint;
CREATE DATABASE
=> \c wal_checkpoint
You are now connected to database "wal_checkpoint" as user "postgres".
=> CREATE TABLE test(t text);
CREATE TABLE
=> INSERT INTO test VALUES ('Перед сбоем');
INSERT 0 1
=> \q
postgres$ pg_ctl -w -D /usr/local/pgsql/data stop -m immediate
waiting for server to shut down.... done
server stopped

Сейчас на диске находятся журнальные записи, но табличные страницы не были сброшены на диск.

Проверим состояние кластера:

postgres$ pg_controldata | grep state
Database cluster state:               in production

Состояние не изменилось. При запуске PostgreSQL поймет, что произошел сбой и требуется восстановление.


postgres$ pg_ctl -w -l /home/postgres/logfile -D /usr/local/pgsql/data start
waiting for server to start.... done
server started
postgres$ tail -n 7 /home/postgres/logfile
2019-08-12 17:15:48.053 MSK [10010] LOG:  database system was interrupted; last known up at 2019-08-12 17:15:47 MSK
2019-08-12 17:15:48.841 MSK [10010] LOG:  database system was not properly shut down; automatic recovery in progress
2019-08-12 17:15:48.845 MSK [10010] LOG:  redo starts at 0/1C35C78
2019-08-12 17:15:48.846 MSK [10010] LOG:  invalid record length at 0/1C59A00: wanted 24, got 0
2019-08-12 17:15:48.846 MSK [10010] LOG:  redo done at 0/1C599DC
2019-08-12 17:15:48.846 MSK [10010] LOG:  last completed transaction was at log time 2019-08-12 17:15:47.80934+03
2019-08-12 17:15:48.880 MSK [10009] LOG:  database system is ready to accept connections

student$ psql wal_checkpoint
=> SELECT * FROM test;
      t      
-------------
 Перед сбоем
(1 row)

Как видим, таблица и данные восстановлены.


Теперь остановим экземпляр штатным способом:

=> \q
postgres$ pg_ctl -w -D /usr/local/pgsql/data stop
waiting for server to shut down.... done
server stopped

При такой остановке PostgreSQL выполняет контрольную точку, чтобы сбросить на диск все данные.


Проверим состояние кластера:

postgres$ pg_controldata | grep state
Database cluster state:               shut down

Теперь состояние - "shut down", что соответствует корректной остановке.


Мониторинг

Снова запустим экземпляр.

postgres$ pg_ctl -w -l /home/postgres/logfile -D /usr/local/pgsql/data start
waiting for server to start.... done
server started
student$ psql wal_checkpoint

Параметр checkpoint_warning выводит предупреждение, если контрольные точки, вызванные переполнением размера журнальных файлов, выполняются слишком часто. Его значение по умолчанию:

=> SHOW checkpoint_warning;
 checkpoint_warning 
--------------------
 30s
(1 row)

Его следует привести в соответствие со значением checkpoint_timeout.


Параметр log_checkpoints позволяет получать в журнале сообщений сервера информацию о выполняемых контрольных точках. По умолчанию параметр выключен:

=> SHOW log_checkpoints;
 log_checkpoints 
-----------------
 off
(1 row)

Включим его.

=> ALTER SYSTEM SET log_checkpoints = on;
ALTER SYSTEM
=> SELECT pg_reload_conf();
 pg_reload_conf 
----------------
 t
(1 row)


Теперь запишем что-нибудь в таблицу и выполним контрольную точку.

=> INSERT INTO test
SELECT g.id::text FROM generate_series(1,100000) AS g(id);
INSERT 0 100000
=> CHECKPOINT;
CHECKPOINT

Вот какую информацию можно будет узнать из журнала сообщений:

postgres$ tail -n 2 /home/postgres/logfile
2019-08-12 17:15:49.761 MSK [10148] LOG:  checkpoint starting: immediate force wait
2019-08-12 17:15:49.791 MSK [10148] LOG:  checkpoint complete: wrote 442 buffers (2.7%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.004 s, sync=0.017 s, total=0.030 s; sync files=2, longest=0.015 s, average=0.008 s; distance=6226 kB, estimate=6226 kB

Статистика работы процессов контрольной точки и фоновой записи отражается в одном общем представлении (раньше обе задачи решались одним процессом; затем их функции разделили, но представление осталось).

=> SELECT * FROM pg_stat_bgwriter \gx
-[ RECORD 1 ]---------+------------------------------
checkpoints_timed     | 0
checkpoints_req       | 1
checkpoint_write_time | 4
checkpoint_sync_time  | 17
buffers_checkpoint    | 442
buffers_clean         | 0
maxwritten_clean      | 0
buffers_backend       | 444
buffers_backend_fsync | 0
buffers_alloc         | 630
stats_reset           | 2019-08-12 17:15:48.881345+03

* checkpoints_timed - контрольные точки по расписанию (checkpoint_timeout);

* checkpoints_req - контрольные точки по требованию (max_wal_size);

* buffers_checkpoint - страницы, сброшенные при контрольных точках;

* buffers_backend - страницы, сброшенные обслуживающими процессами;

* buffers_clean - страницы, сброшенные процессом фоновой записи;


В хорошо настроенной системе значение buffers_backend должно быть существенно меньше, чем сумма buffers_checkpoint и buffers_clean.

Большое значение checkpoint_req (по сравнению с checkpoints_timed) говорит о том, что контрольные точки происходят чаще, чем предполагалось.

Конец демонстрации.