Добавил:
ИВТ (советую зайти в "Несортированное")rnПИН МАГА Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Database 2024 / Books / Мониторинг PostgreSQL.pdf
Скачиваний:
26
Добавлен:
20.11.2024
Размер:
6.87 Mб
Скачать

Глава 6

Журнал упреждающей записи

Вэтой главе мы рассмотрим:

что такое журнал упреждающей записи;

устройство журнала упреждающей записи в PostgreSQL;

как отслеживать активность,связанную с журналом;

представление pg_stat_wal;

отслеживание записи в журнал запросами;

архивирование сегментов журнала;

представление pg_stat_archiver;

способы отслеживания проблем при архивировании журнала;

отслеживание очереди архивирования журнала.

Вэтой главе мы рассмотрим журнал упреждающей записи, он же журнал предзаписи (WriteAhead Log), который в том или ином виде присутствует в большинстве СУБД. Журнал предзаписи в общем виде представляет собой историю всех изменений данных, происходящих в СУБД. В случае аварий такая история позволяет воспроизвести всю последовательность изменений до момента аварии и восстановить актуальное и согласованное состояние СУБД.

Вэтой главе мы кратко рассмотрим устройство журнала (здесь и далее в этой главе подтерми- ном«журнал»будетподразумеватьсяименноWAL-журнал,анежурналсообщенийСУБД)ибо- лее подробно рассмотрим инструменты и способы отслеживания событий, связанных с журналом.

6.1. Write-Ahead Log —журнал упреждающей записи

Для гарантий надежности все изменения данных в СУБД должны быть записаны в надежное хранилище (обычно на диск). Нельзя допускать искажений, повреждений и тем более потери данныхдажевслучаесбоеввсистеме.ДляреализацииэтихтребованийпрактическивсеСУБД используютжурнал предзаписи.В PostgreSQL журнал представляетсобой историю изменений данных,иСУБДвслучаеавариииспользуетжурналдлявоспроизведенияэтихизмененийидостижения последней согласованной точки до момента аварии.

Экземпляр СУБД состоит из множества клиентских и фоновых процессов, которые работают с данными, размещенными в общей памяти, — к таким данным относятся и буферный

158Глава 6. Журнал упреждающей записи

кеш с пользовательскими данными, и служебные структуры данных. Приложения отправляют запросы, а СУБД выполняет их. В случае запросов на чтение СУБД обращается к данным и возвращает необходимый набор строк; в случае запросов на изменение данных (или схемы) СУБД вносит соответствующие изменения.Все изменения происходят в общей памяти,затем в отложенном режиме процесс фоновой записи или контрольной точки синхронизирует изменения в кеше с основным хранилищем. Общая память СУБД является оперативной, и ее содержимое не защищено отсистемных сбоев вроде отказов питания.Также существуеткласс программных ошибок,при которых областьобщей памяти можетбытьповреждена и потребуется ее полная очистка и пересоздание—как правило,это ошибки сегментации (segmentation fault). К подобным последствиям приводит и аварийное завершение операционной системой каких-либо процессов СУБД.Обычнотакие аварийные ситуации происходятвнезапно,нельзя подготовиться к ним заранее и ждать их наступления в известный момент. Получается, что СУБД нужен инструмент, позволяющий восстановить те изменения данных, которые произошли в общей памяти,но из-за аварии не были записаны в основное хранилище.

Однако СУБД может эксплуатироваться очень долго, и хранить абсолютно всю историю изменений невозможно (либо это требует значительных или даже неадекватных экономических вложений). Для повторного использования файлов журнала и поддержания его в разумных объемах применяются контрольные точки: все изменения, предшествующие такой точке, гарантированно записаны в основное хранилище данных,которое считается надежным.Отметки об успешном завершении контрольных точек также записываются в журнал, после чего часть журнала до контрольной точки может быть удалена. В случае аварии остается воспроизвести только те изменения, которые были записаны в журнал после контрольной точки, и прийти к состоянию до момента аварии.

На практике журнал представляетсобой набор файлов (сегментов) внутри подкаталога pg_wal

восновном каталоге данных:

#ls -l /var/lib/postgresql/data/pg_wal/ total 196616

-rw-------

1

postgres postgres

341

Nov

4

05:03 000000010000000000000011.0001F7A0.backup

-rw-------

1

postgres postgres

16777216

Nov

18

05:26 000000010000004B000000C2

-rw-------

1

postgres postgres

16777216

Nov

18

05:27 000000010000004B000000C3

-rw-------

1

postgres postgres

16777216

Nov

18

05:28 000000010000004B000000C4

-rw-------

1

postgres postgres

16777216

Nov

18

05:28 000000010000004B000000C5

-rw-------

1

postgres postgres

16777216

Nov

18

05:29 000000010000004B000000C6

-rw-------

1

postgres postgres

16777216

Nov

18

05:30 000000010000004B000000C7

-rw-------

1

postgres postgres

16777216

Nov

18

05:31 000000010000004B000000C8

-rw-------

1

postgres postgres

16777216

Nov

18

05:32 000000010000004B000000C9

-rw-------

1

postgres postgres

16777216

Nov

18

05:24 000000010000004B000000CA

-rw-------

1

postgres postgres

16777216

Nov

18

05:20 000000010000004B000000CB

-rw-------

1

postgres postgres

16777216

Nov

18

05:25 000000010000004B000000CC

-rw-------

1

postgres postgres

16777216

Nov

18

05:23 000000010000004B000000CD

drwx------

2

postgres postgres

4096

Nov

18

05:31 archive_status

Все сегменты журнала имеют имя из 24 цифр в шестнадцатеричном формате без расширения. Имя состоит из трех октетов (на примере сегмента 000000010000004B000000CD):

6.1. Write-Ahead Log—журнал упреждающей записи

159

1.00000001— идентификатор линии времени (timeline id). Линии времени используется механизмом восстановления на точку во времени (Point-in-Time Recovery,PITR)1,2.

2.0000004B — идентификатор верхнего диапазона сегментов со значениями от 00000000

до FFFFFFFF.

3.000000CD — идентификатор нижнего диапазона сегментов со значениями от 00000000, а последний номер зависит от размера сегмента, заданного при инициализации основного каталога.

Каждый сегмент имеет фиксированный размер (см. wal_segment_size), по умолчанию 16 МБ. Внутри каждый сегмент поделен на блоки по 8 КБ (см. wal_block_size). Размер сегмента можно менять при инициализации кластера (параметр --wal-segsize). Каждый блок содержит WALзаписи(records)внепечатаемомдвоичномформате,описывающиеотдельныеизмененияданных. Одна такая запись содержит достаточно информации для воспроизведения (повторного применения) одного конкретного изменения в случае сбоя системы. Записи могут иметь разные типы и относиться к изменениям самых разных объектов. Для анализа содержимого журнала можно использовать утилиту pg_waldump3 или расширение pg_walinspect4. Оба инструмента предоставляютодинаковую функциональность,но первый предназначендля ра- ботытольковсредетерминала,арасширениепредоставляетSQL-интерфейссболеебогатыми возможностями для анализа результатов:

# SELECT * FROM pg_get_wal_records_info('4B/DF000000','4B/E0000000') LIMIT 14;

start_lsn | end_lsn | prev_lsn | xid

| resource_manager | record_type | record_length | main_data_length | fpi_length |

-------------+-------------+-------------+----------+------------------+-------------+---------------+------------------+------------+-----------...

4B/DF000350 | 4B/DF0003F8 | 4B/DEFFE370 | 43601290

| Heap

| HOT_UPDATE

|

163

|

14

|

0

| off 88 xma...

4B/DF0003F8 | 4B/DF000448 | 4B/DF000350 | 43601290

| Heap

| HOT_UPDATE

|

78

|

14

|

0

| off 22 xma...

4B/DF000448 | 4B/DF000498 | 4B/DF0003F8 | 43601290

| Heap

| HOT_UPDATE

|

74

|

14

|

0

| off 111 xm...

4B/DF000498 | 4B/DF0004E8 | 4B/DF000448 | 43601290

| Heap

| INSERT

|

79

|

3

|

0

| off 43 fla...

4B/DF0004E8 | 4B/DF000518 | 4B/DF000498 | 43601290

| Transaction

| COMMIT

|

46

|

20

|

0

| 2022-11-18...

4B/DF000518 | 4B/DF0024E8 | 4B/DF0004E8 |

0

| Heap2

| PRUNE

|

8119

|

8

|

8060

| latestRemo...

4B/DF0024E8 | 4B/DF002590 | 4B/DF000518 | 43601291

| Heap

| HOT_UPDATE

|

163

|

14

|

0

| off 104 xm...

4B/DF002590 | 4B/DF0025E0 | 4B/DF0024E8 | 43601291

| Heap

| HOT_UPDATE

|

78

|

14

|

0

| off 71 xma...

4B/DF0025E0 | 4B/DF002630 | 4B/DF002590 | 43601291

| Heap

| HOT_UPDATE

|

74

|

14

|

0

| off 133 xm...

4B/DF002630 | 4B/DF002680 | 4B/DF0025E0 | 43601291

| Heap

| INSERT

|

79

|

3

|

0

| off 27 fla...

4B/DF002680 | 4B/DF0026B0 | 4B/DF002630 | 43601291

| Transaction

| COMMIT

|

46

|

20

|

0

| 2022-11-18...

4B/DF0026B0 | 4B/DF004680 | 4B/DF002680 |

0

| Heap2

| PRUNE

|

8119

|

8

|

8060

| latestRemo...

4B/DF004680 | 4B/DF004728 | 4B/DF0026B0 | 43601292

| Heap

| HOT_UPDATE

|

163

|

14

|

0

| off 78 xma...

4B/DF004728 | 4B/DF004778 | 4B/DF004680 | 43601292

| Heap

| HOT_UPDATE

|

78

|

14

|

0

| off 179 xm...

Каждая отдельная запись имеет уникальный идентификатор LSN (log sequence number).Идентификатор можно использовать как позицию в WAL-журнале, по которой можно определить местоположение записи в журнале.На примере записи 4B/DF0026B0:

4B—идентификатор верхнего диапазона (второй октет имени файла сегмента);

DF—идентификатор нижнего диапазона (третий октет имени файла сегмента);

0026B0—смещение внутри файла сегмента.

1 www.interdb.jp/pg/pgsql10.html#_10.3.1.

2 postgrespro.ru/docs/postgresql/current/continuous-archiving

3 postgrespro.ru/docs/postgresql/current/pgwaldump

4 postgrespro.ru/docs/postgresql/current/pgwalinspect

160Глава 6. Журнал упреждающей записи

Определить сегмент, в котором находится конкретная запись, можно с помощью функции pg_walfile_name,передав ей LSN:

# SELECT pg_walfile_name('4B/DF008B78'); pg_walfile_name

--------------------------

000000010000004B000000DF

При активной эксплуатации СУБД и постоянном измененииданных в журнал вставляются новые записи итекущая позиция (выраженная в LSN) постоянно смещается вперед.После вставкидобавленныезаписиследуетнадежнозаписатьивосновноехранилище.Получитьтекущую позицию записи журнала можно с помощью нескольких функций:

pg_current_wal_insert_lsn—позиция последней вставленной в журнал записи;

pg_current_wal_lsn—позиция последней сохраненной на диск записи;

pg_current_wal_flush_lsn — позиция последней сохраненной и синхронизированной с диском записи.

При полном заполнении сегмента вставка начинается в следующий по порядку сегмент.

Объем WAL-журнала ограничен параметрами конфигурации и при нормальной эксплуатации количество сегментов колеблется в определенном диапазоне. При пиковых нагрузках, особенно связанных с изменением данных, могут создаваться дополнительные сегменты, отчего размер журнала может увеличиваться. При возвращении нагрузки к нормальным значениям и после выполнения контрольной точки размер журнала скорректируется — излишние сегменты будут либо удалены, либо переименованы для использования в будущем; таким образом объем журнала уменьшится до размеров, заданных в конфигурации СУБД. В следующем листинге по отметкам времени можно заметить, что запись идет в сегмент 000000010000004B000000FC, а сегменты с бóльшими номерами, но меньшим временем зарезервированы под использование в ближайшем будущем — как только активный сегмент будет заполнен,СУБД переключится на запись в следующий сегмент.

# ls -l /var/lib/postgresql/data/pg_wal/

 

 

 

total 196616

 

 

 

 

 

 

-rw-------

1

postgres postgres

341

Nov

4

05:03 000000010000000000000011.0001F7A0.backup

-rw-------

1

postgres postgres

16777216

Nov

18

06:21 000000010000004B000000F5

-rw-------

1

postgres postgres

16777216

Nov

18

06:22 000000010000004B000000F6

-rw-------

1

postgres postgres

16777216

Nov

18

06:23 000000010000004B000000F7

-rw-------

1

postgres postgres

16777216

Nov

18

06:24 000000010000004B000000F8

-rw-------

1

postgres postgres

16777216

Nov

18

06:25 000000010000004B000000F9

-rw-------

1

postgres postgres

16777216

Nov

18

06:26 000000010000004B000000FA

-rw-------

1

postgres postgres

16777216

Nov

18

06:27 000000010000004B000000FB

-rw-------

1

postgres postgres

16777216

Nov

18

06:28 000000010000004B000000FC <<< активный сегмент

-rw-------

1

postgres postgres

16777216

Nov

18

06:17 000000010000004B000000FD

-rw-------

1

postgres postgres

16777216

Nov

18

06:16 000000010000004B000000FE

Соседние файлы в папке Books