64-битные идентификаторы транзакций
Описание механизма
В ядре оригинального PostgreSQL для невиртуальных идентификаторов транзакций (TransactionId, или XID) выделено 32 бита, которые покрывают всего 4 млрд транзакций. Во избежание исчерпания номеров транзакций применяется закольцованная схема счетчика транзакций.

Чтобы понять, какая транзакция произошла раньше, а какая позже, используются определения «старше» и «младше» вместо «меньше» и «больше». Все пространство номеров транзакций (XID) в количестве, равном , поделено на 2 половины:
- номера транзакций, отстоящие на - от текущей, находятся в прошлом;
- номера транзакций, отстоящие на + от текущей, считаются в будущем.
Логическое сравнение двух номеров транзакций выполняется путем приведения их значений к началу отсчета (ноль) и сравнения разницы получившихся значений с половиной всего диапазона номеров . Если результат меньше , то первый номер транзакции предшествует второму номеру, то есть старше, иначе – следует после второго номера, а значит, младше. Ниже приведена формула для определения, предшествует ли транзакция xid1 транзакции xid2:
Например, определим, старше ли транзакция с номером 3 000 000 000 (xid1) транзакции с номером 1 000 (xid2):
В закольцованной схеме транзакция 3 000 000 000 оказывается старше транзакции 1 000, а в прямой последовательной схеме транзакция была бы младше.
На рисунке «Закольцованная схема счетчика транзакций» текущая транзакция 100 будет старше транзакции +100 (транзакция +100 в будущем):
Но младше транзакции +100 (транзакция +100 в прошлом):
Использование закольцованного пространства номеров счетчика транзакций может привести к проблеме видимости версий строк (кортежей) в механизме многоверсионности (MVCC) СУБД Pangolin. В заголовке каждой версии строки таблицы хранятся номера транзакций в полях:
t_xmin– 32-битное значение номера транзакции, создавшей строку;t_xmax– 32-битное значение номера транзакции, удалившей строку.
Организация хранения данных в СУБД Pangolin:

В каждой транзакции видимость версий строк таблиц определяется согласно установленным правилам в соответствии с созданным снимком данных. Версия строки видна, если в снимке видны изменения, сделанные транзакцией, чей номер указан в поле t_xmin заголовка версии строки, то есть проверяется, что t_xmin старше xmin в снимке данных, где xmin – номер самой ранней активной транзакции в системе (транзакции с номерами старше номера xmin точно зафиксированы). Проблема видимости строк возникает при увеличении счетчика, когда номер транзакции t_xmin в заголовке версии строки становится младше xmin из снимка данных, то есть версия строки оказывается в будущем для текущей транзакции, что трактуется как повреждение данных.
На рисунке «Проблема видимости строк при использовании закольцованной схемы счетчика транзакций» версия строки, созданная транзакцией +101 пропадает для текущей активной транзакции 101 (он же xmin в снимке данных), поскольку 101 теперь предшествует +101:

Важным условием использования закольцованной схемы номеров транзакций является отсутствие в какой-либо из таблиц БД версий строк, возраст которых превышает 2 млрд транзакций и в которых не проставлены флаги (hint bits), указывающие на то, что строки уже достаточно старые, чтобы быть видимыми всем текущим транзакциям (во всех снимках). Процесс установки данных флагов называется заморозкой, а версии строк – замороженными. Замороженные версии строк всегда остаются в прошлом. Идентификаторы транзакций в полях t_xmin этих версий строк могут быть безопасно переиспользованы.
Заморозка старых версий строк для решения проблемы видимости:

Заморозка может выполняться процессом автоочистки (autovacuum), либо вручную командой vacuum freeze. Настройка выполняется тремя параметрами:
vacuum_freeze_min_age(50 000 000) - возраст транзакции, начиная с которой заодно с очисткой страниц будет происходить заморозка;vacuum_freeze_table_age(150 000 000) - при достижении такого возраста замораживаются версии строк на всех страницах таблицы (агрессивная заморозка);autovacuum_freeze_max_age(200 000 000) - начиная с этого возраста, запускается принудительная заморозка, даже если она была отключена.

При частых переполнениях счетчика транзакций затраты на эту процедуру оказываются существенными: осуществляется лишний доступ к диску и увеличивается размера журнала предзаписи. На рисунке далее представлен возможный жизненный цикл одной из страниц таблицы:
- Таблица модифицируется. В страницу буферного кеша добавляются версии строк, эти же строки пишутся в WAL.
- Наступает момент записи контрольной точки (
CHECKPOINT). «Грязная» страница записывается в файл таблицы. Посколькуautovacuumпо ней не проходил, версии строк страницы остались незамороженными. - Автоочистка (
autovacuum) принимает решение заморозить версии строк, расположенные на этой странице. В худшем случае страница могла быть вытеснена на диск, тогда автовакууму придется прочитать ее с диска. После выполнения контрольной точки, при первом изменении страницы, ее содержимое целиком записывается в WAL (Full Page Write), даже если изменилось всего несколько бит во флагах заголовка версии строки. - Процесс контрольной точки (
CHECKPOINT) снова записывает страницу на диск.
При следующем изменении страницы ее жизненный цикл может повториться.

Если заморозка не будет успевать обрабатывать версии строк, то возраст самой старой незамороженной транзакции может приблизиться к 2 млрд, вследствие чего Pangolin не сможет больше выдавать номера транзакций для запросов на запись, требуя ручного вмешательства и проведения очистки/заморозки в однопользовательском режиме:
ERROR: database is not accepting commands to avoid wraparound data loss in database "postgres"
HINT: Stop the postmaster and vacuum that database in single-user mode.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
В СУБД Pangolin используются и 64-битные идентификаторы транзакций (тип xid8), добавляющие к короткому идентификатору общую для всего кластера 32-битную эпоху (поле Latest checkpoint's NextXID в контрольном файле), но только для служебных целей, и это не решает проблему переполнения счетчика. 64-битные идентификаторы транзакций используются, например, в выдаче результата выполнения SQL-функции pg_current_xact_id(). Они существуют только в памяти и не попадают в страницы данных. Эпоха обновляется в контрольном файле при выполнении CHECKPOINT в контрольном файле (указывается перед двоеточием):
pg_controldata -D /opt/pgdata-5xx/ | grep NextXID
Latest checkpoint's NextXID: 0:724 # 0 - эпоха
Помимо механизма обычных транзакций (включая вложенные) в СУБД Pangolin реализован механизм мультитранзакций, применяемый для разделяемых блокировок. Для выделения номеров мультитранзакций используется свой независимый счетчик, то есть номера транзакций и мультитранзакций могут пересекаться. Счетчик мультитранзакций закольцован так же, как и счетчик обычных транзакций. При активном использовании разделяемых блокировок счетчик мультитранзакций может переполниться, что приведет к тем же проблемам, что и при переполнении счетчика обычных транзакций: отказ в обслуживании при долгоживущей мультритранзакции и частая заморозка мультитранзакций.
Описание решения
В СУБД Pangolin реализовано увеличение разрядности счетчиков обычных транзакций и мультитранзакций до 64-бит.
Назначение
Переход на 64-битный счетчик транзакций решает проблему их переполнения, делая этот момент практически недостижимым. Даже при нагрузке транзакций в день (~50 000 TPS) граница раздела между прошлым и будущим будет достигнута через дней (5,9 млн лет). В результате появляется возможность:
-
Не отказывать в выполнении обновляющих запросов при высокой транзакционной нагрузке, если
autovacuumне успевает выполнить заморозку во всех БД или имеется долгоживущая транзакция.В случае 32-битного счетчика 13 часовой OLAP-запрос стал бы причиной отказа в обслуживании OLTP-запросов со скоростью 50 000 TPS спустя 12 часов. К этому моменту возраст самой старой транзакции достиг бы . Горизонт транзакций (
xmin), удерживаемый OLAP-запросом, не даетautovacuumзаморозить версии строк младше горизонта транзакций для продвижения счетчика. В результате новый номер для пишущей транзакции не выделяется и Pangolin завершает OLTP-запросы с ошибкой, чтобы не допустить потерю данных.64-битный счетчик снимает ограничение на предельный возраст самой старой транзакции , поэтому рассмотренная выше проблема отсутствует.
-
Снизить риск деградации производительности при интенсивной транзакционной нагрузке за счет настройки более редкого запуска процедуры заморозки и ее планирования на период с меньшей нагрузкой. В случае использования 32-битного счетчика частота выполнения заморозки определяется ограничением по возрасту самой старой версии строки, который не должен превышать 2 млрд транзакций.
Настройка
Конфигурационные параметры
Добавлены новые GUC-параметры для настройки функциональности:
Параметр | Описание | Значение по умолчанию | Применение параметра |
|---|---|---|---|
| Параметр определяет, как часто в WAL будут записываться полные образы страниц, преобразованных в формат | Значением по умолчанию Диапазон значений: | Изменение параметра доступно без перезапуска сервера СУБД |
| Параметр ограничивает число SLRU-страниц, зарезервированных для уведомлений в механизме | Значение по умолчанию Диапазон значений | Для изменения параметра требуется перезапуск сервера СУБД |
Также изменены максимальные значения и значения по умолчанию следующих параметров:
| Параметр | Значение по умолчанию (было → стало) | Максимальное значение (было → стало) |
|---|---|---|
vacuum_freeze_min_age | без изменений | 1000000000 → 0x7FFFFFFFFFFFFFFF |
vacuum_freeze_table_age | без изменений | 2000000000 → 0x7FFFFFFFFFFFFFFF |
vacuum_multixact_freeze_min_age | без изменений | 1000000000 → 0x7FFFFFFFFFFFFFFF |
vacuum_multixact_freeze_table_age | без изменений | 2000000000 → 0x7FFFFFFFFFFFFFFF |
autovacuum_freeze_max_age | 200000000 → 10000000000 | 2000000000 → 0x7FFFFFFFFFFFFFFF |
autovacuum_multixact_freeze_max_age | 400000000 → 20000000000 | 2000000000 → 0x7FFFFFFFFFFFFFFF |
Следующие параметры конфигурации не используются: vacuum_defer_cleanup_age, vacuum_failsafe_age, vacuum_multixact_failsafe_age. В следующих версиях планируется их исключение из списка возможных параметров.
Управление
Новый формат страницы
64-битные номера транзакций требуется сохранять на диске: в полях t_xmin и t_xmax в заголовках версий строк и в pd_prune_xid в заголовке страницы. Прямой метод увеличения разрядности этих полей до 8 байт приведет к существенному расходу дискового пространства и потребует переупаковки каждой версии строки при обновлении через pg_upgrade, поэтому вводится новый формат страницы при сохранении формата версии строки, то есть разрядность t_xmin и t_xmax остается 32-битной. В конце каждой страницы резервируется место под специальную область для трех полей: pd_xid_base, pd_multi_base и pd_magic.

В полях pd_xid_base и pd_multi_base хранятся базовые значения, относительно которых вычисляются 64-битные номера транзакций. Поле pd_magic используется как маркер для обозначения типа страниц, чтобы отличать их от индексных страниц, у которых тоже есть специальная область.
В TOAST-таблицах не применяется механизм мультитранзакций, поэтому в специальной области страниц этих объектов хранится одна база pd_xid_base и «магическое» число pd_magic.
Данные в специальное области страницы:
| Поле | Размер | Описание |
|---|---|---|
pd_xid_base | 8 байт | База для коротких 4-байтных идентификаторов транзакций на этой странице (поля заголовков версий строк t_xmin, t_xmax и поле заголовка страницы pd_prune_xid) |
pd_multi_base | 8 байт | База для коротких 4-байтных идентификаторов мультитранзакций на этой странице (поле заголовков версий строк t_xmax). Отсутствует в страницах TOAST-таблиц |
pd_magic | 4 байта | Зарезервированное число, обозначающее тип страницы: 0x1010 – для обычной, партиционированной или TOAST-таблицы; 0x1717 – для последовательности. |
64-битные номера транзакций t_xmin и t_xmax в заголовке версии строки вычисляются при каждом доступе к ней следующим образом:

Поскольку базовое значение общее для всей страницы, то на одной странице не могут быть размещены строки, созданные транзакциями, разница в возрасте которых превышает 4 млрд транзакций ().
Сократить разрядность базы до 4-х байт и использовать формулы, представленные ниже, не представляется возможным.
Если значение базы будет кратным , то при вставке новой версии строки в страницу и пересечении текущим идентификатором транзакции границы значение базы инкрементируется, что приведет к инвалидации значений полей t_xmin/t_xmax актуальных версий строк: транзакции окажутся в будущем. Например, на странице есть одна строка с t_xmin равным 3 млрд, база pd_xid_base равна 0. Чтобы добавить в эту же страницу строку с номером транзакции 5 млрд, потребуется инкрементировать pd_xid_base (будет 1) и результат вычитания 4 млрд из 5 млрд присвоить t_xmin (1 млрд). Увеличение pd_xid_base привело бы к увеличению t_xmin существующей версии строки с 3 млрд до 7 млрд. В результате версия строки окажется невидимой для текущей транзакции.
Удаление или обновление версии строки
При удалении, либо обновлении строки выполняется проверка, что текущий идентификатор транзакции (), в сочетании с базой, не пересекает границу (). Если условие удовлетворяется, то полю строки t_xmax (в случае удаления/обновления) присваивается значение . Если нет, то корректируется база и обновляются поля t_xmin/t_xmax во всех версиях строк на странице. Если базу не удалось подстроить в силу наличия версий строк, созданных старыми транзакциями, выполняется удаление мертвых версий строк и заморозка оставшихся старых версий строк на этой странице. Если после этих действий не удалось изменить базу, выдается ошибка.

Вставка новой версии строки
При вставке строки выполняется проверка, что текущий идентификатор транзакции (), в сочетании с базой, не пересекает границу (). Если условие удовлетворяется, то полю строки t_xmin присваивается значение . Если нет, то корректируется база и обновляются поля t_xmin/t_xmax во всех версиях строк на странице. Если базу не удалось подстроить в силу наличия версий строк, созданных старыми транзакциями, выполняется удаление неактуальных версий строк и заморозка оставшихся старых версий строк на этой странице. Если после этих действий не удалось изменить базу, выдается ошибка.

Очистка страницы от мертвых версий строк и заморозка старых могут не отработать из-за висящих, долгих транзакций, незавершенных подготовленных транзакций и неактивных слотов репликации.
Изменения в WAL
-
Изменен порядок полей в заголовке WAL записи
XLogRecordдля сокращения размера заголовка:Старый формат Размер Новый формат Размер xl_tot_len4 байта xl_tot_len4 байта xl_xid4 байта xl_crc4 байта xl_prev8 байт xl_xid8 байт xl_info1 байт xl_prev8 байт xl_rmid1 байт xl_info1 байт padding2 байта для выравнивания на границе 4 байтов xl_rmid1 байт xl_crc4 байта Размер заголовка WAL-записи в старом формате 24 байта, в новом - 26 байт.
-
Добавлена новая WAL-запись
Heap3с информацией о корректировке базового значения:- «desc: BASE_SHIFT XactId» - для
pd_xid_base; - «desc: BASE_SHIFT MultiXactId» - для
pd_multi_base.
rmgr: Heap3 len (rec/tot): 58/ 58, tx: 4294968069, lsn: 0/02A5ED88, prev 0/02A5EC68, desc: BASE_SHIFT XactId delta 4294967293 , blkref #0: rel 1663/5/16444 blk 539
rmgr: Heap3 len (rec/tot): 58/ 58, tx: 4294968069, lsn: 0/02A5ED88, prev 0/02A5EC68, desc: BASE_SHIFT MultiXactId delta 4294967293 , blkref #0: rel 1663/5/16444 blk 539 - «desc: BASE_SHIFT XactId» - для
-
Добавлена дедупликация WAL-записей заморозки версий строк для сокращения размера WAL (один план заморозки теперь может включать несколько версий строк, если их планы совпадают):
rmgr: Heap2 len (rec/tot): 127/ 127, tx: 0, lsn: 0/02556C20, prev 0/02556BD8, desc: FREEZE_PAGE latestRemovedXid 790 nplans 1, blkref #0: rel 1663/1/2619 blk 23
rmgr: Heap2 len (rec/tot): 137/ 137, tx: 0, lsn: 0/02556CE8, prev 0/02556CA0, desc: FREEZE_PAGE latestRemovedXid 790 nplans 2, blkref #0: rel 1663/1/2619 blk 24
rmgr: Heap2 len (rec/tot): 133/ 133, tx: 0, lsn: 0/02556DC0, prev 0/02556D78, desc: FREEZE_PAGE latestRemovedXid 790 nplans 3, blkref #0: rel 1663/1/2619 blk 25
rmgr: Heap2 len (rec/tot): 285/ 285, tx: 4294968069, lsn: 0/02A5EC68, prev 0/02A5EC20, desc: FREEZE_PAGE latestRemovedXid 4294968068 nplans 1, blkref #0: rel 1663/5/16444 blk 539 -
Повышена версия страницы WAL в ее заголовке: .
Обновление
При обновлении СУБД с переносом данных с версии ранее чем 6.1.0 будет задействована утилита pg_upgrade. Утилита pg_upgrade выполняет следующие действия:
-
Проверяет, есть ли в обновляемой СУБД пользовательские таблицы со столбцами типа
xid. Если есть, выводит сообщение с требованием их удалить перед обновлением. Список таких объектов БД перечислен в файлеtables_using_xid.txt.Checking for incompatible "xid" data type fatal
Your installation contains the "xid" data type in user tables.
The internal format of "xid" changed in Pangolin 6.1.0 so this cluster
cannot currently be upgraded. Note that even dropped attributes cause a problem.
You can remove the problem tables and restart the upgrade.
A list of the problem columns is in the file:
tables_using_xid.txtВ скрипт-разведчик добавлена аналогичная проверка. Пример сообщения:
{{ control_name }}.FAIL__Обнаружена(ы) таблица(ы) в которой(ых) присутствует(ют) поле(я) с типом xid.
В новой версии СУБД Pangolin применяется 64-битный счетчик транзакций.
Необходимо удалить поле(я) с типом xid в таблице(ах).
Список таблиц, использующих их (<имя таблицы>(<имя колонки>)):
types04.typ_xid(val),
types04.typ_xid(val_arr),
types05fail.typ_pgc_pg_class(val),
types05fail.typ_pgc_pg_class(val),
types05fail.typ_pgc_pg_database(val),
types05fail.typ_pgc_pg_database(val).{{ control_name }}.FAIL -
Инвалидирует индексы и создает SQL-скрипты (
reindex_spgist.sql,reindex_gin.sql,reindex_external.sql) для их перестроения:Checking for spgist indexes warning
Your installation contains spgist indexes. These indexes have different
internal formats between your old and new clusters, so they must be
reindexed with the REINDEX command. The file
reindex_spgist.sql
when executed by psql by the database superuser will recreate all invalid
indexes; until then, none of these indexes will be used.
Checking for gin indexes warning
Your installation contains gin indexes. These indexes have different
internal formats between your old and new clusters, so they must be
reindexed with the REINDEX command. The file
reindex_gin.sql
when executed by psql by the database superuser will recreate all invalid
indexes; until then, none of these indexes will be used. -
Копирует файлы карт видимости (VM) и свободного пространства (FSM), устанавливая новую версию страниц, чтобы не выполнять это действие лениво в работающей СУБД.
-
Переносит файлы из директории обновляемой СУБД
PGDATA/pg_xactв новую папку, выполняя обработку переполнения счетчика (если оно произошло в обновляемой БД) и переименовывая сегменты файлов. При использовании 32-битного счетчика выполнялась ротация таких файлов из-за переполнения счетчика, а в случае с 64-битным счетчиком переполнение не возможно, поэтому для поступающих транзакций всегда создаются новые файлы. Имена файлов расширены до 15 символов, чтобы не путать их с WAL-файлами:32 бит 64 бит
0000 -> 000000000000000
0001 -> 000000000000001
...
0FFE -> 000000000000FFE
0FFF -> 000000000000FFF
0000 -> 000000000001000
0001 -> 000000000001001 -
Переносит файлы из директорий обновляемой
PGDATA/pg_multixact(offsetsиmembers) в новую, выполняя обработку переполнения счетчика (если оно произошло в обновляемой БД) и переименовывая сегменты файлов. В файлахoffsetsссылки наmembersбудут начинаться с 1. В файлахmembersзаписи сXIDстанут 64-битными. -
Устанавливает текущий счетчик в , чтобы номера транзакций, созданных после обновления, были младше номеров транзакций, которые существовали до обновления.
-
Выполняет обработку переполнения счетчика в обновляемой СУБД в случае, когда следующее значение счетчика
NextXIDперешагнуло через максимальное значениеUINT32(4 млрд), а номер самой старой незамороженной транзакции (datfrozenxid) еще нет. Поскольку новое значение счетчикаNextXIDв обновленной СУБД устанавливается в , нельзя оставлять прежнее значениеdatfrozenxid(-100), так как это означало бы, что все транзакции до этого значения в обновленной СУБД заморожены, но это не так: транзакции с 3 поNextXIDмогут остаться незамороженными, поэтому значениеdatfrozenxidустанавливается в значение 3 (первый неслужебный номер транзакции).

Обновление посредством pg_upgrade не конвертирует страницы таблиц в новый формат 64-битных счетчиков транзакций. Эта процедура выполняется на ведущем сервере «лениво» в процессе работы при чтении страниц с диска. Это может снизить производительность после обновления. Каждая переупакованная страница должна приводить к записи в WAL полного образа страницы. Чтобы избежать интенсивной записи в WAL и нагрузки на диск, сразу после старта обновленной СУБД, прочитанные с диска страницы переупаковываются, но полный образ записывается в WAL для каждой 128-й страницы. Частота записи определяется параметром xid64_full_page_write_sampling. Изменение параметра доступно без остановки СУБД. Оставшиеся переупакованные страницы в буферном кеше отмечаются специальным флагом BM_CONVERTED и не маркируются признаком того, что данные на странице изменились (флаг BM_DIRTY), поэтому не будут записываться на диск при их вытеснении. Флаг BM_CONVERTED служит для определения, требуется ли запись в WAL полного образа страницы при первом ее изменении в пишущем запросе или нет.
На резервном сервере при чтении страниц с диска выполняется их переупаковка в 64-битный формат, а буферы, содержащие эти страницы, отмечаются флагом BM_CONVERTED. Резервный сервер не записывает страницы на диск. Флаг BM_CONVERTED служит для определения, требуется ли запись в WAL полного образа страницы при первом ее изменении в пишущем запросе после повышения резервного сервера до ведущего или нет.
В случае нехватки места на странице для размещения специальной области, конвертация формата страницы откладывается до появления на ней свободного пространства, когда страница преобразуется во временный формат double XMAX. Поскольку после обновления все страницы заведомо заморожены, так как более старые транзакции не могут быть запущены, поле t_xmin больше не требуется и переиспользуется для хранения старших 32 бит XMAX при удалении строки. После очистки страницы формат преобразуется в 64-битный.
Диагностика
В журнале лог-файлов:
-
В вывод статистики по таблицам автоочистки добавлена информация о заморозке версий строк:
LOG: automatic aggressive vacuum of table "template1.pg_catalog.pg_statistic": index scans: 1
pages: 0 removed, 29 remain, 29 scanned (100.00% of total)
...
frozen: 15 pages from table (51.72% of total) had 172 tuples frozen
... -
За неактуальностью исключен вывод сообщений с предупреждением о приближении счетчика к переполнению:
WARNING: database "postgres" must be vacuumed within 10999807 transactions
HINT: To avoid a database shutdown, execute a database-wide VACUUM in that database.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
WARNING: database "postgres" must be vacuumed before 100 more MultiXactIds are used
HINT: Execute a database-wide VACUUM in that database.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
STATEMENT: SELECT * FROM wraparound_test FOR KEY SHARE; -
За неактуальностью исключен вывод сообщений об отказе в выполнении пишущих запросов:
ERROR: database is not accepting commands to avoid wraparound data loss in database "postgres"
HINT: Stop the postmaster and vacuum that database in single-user mode.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
STATEMENT: INSERT INTO wraparound_test(data) VALUES ('wraparound');
database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database "postgres"
HINT: Execute a database-wide VACUUM in that database.
You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
STATEMENT: SELECT * FROM wraparound_test FOR KEY SHARE;
Накладные расходы
Ниже перечислены потенциальные накладные расходы, связанные с использованием функциональности:
-
Процедура заморозки все еще требуется для отслеживания самой старой транзакции для удаления лишних файлов:
- CLOG с состояниями транзакций в директории
PGDATA/pg_xact; - со смещениями мультитранзакций (
offsets) и данными о членах мультитранзакций (members) в директорииPGDATA/pg_multixact; - с информацией о вложенных транзакциях в директории
PGDATA/pg_subtrans.
- CLOG с состояниями транзакций в директории
-
Размер файлов в директориях
PGDATA/pg_multixactиPGDATA/pg_subtransувеличивается, поскольку в них хранятся номера транзакций. Для хранения информации о 2 млрд мультитранзакций необходимо предусмотреть:Директории XID32 XID64 Во сколько раз требуется больше места на диске PGDATA/pg_xact512 Мбайт 512 Мбайт 1 PGDATA/pg_multixact/offsets8 Гбайт 16 Гбайт 2 PGDATA/pg_multixact/members10,2 Гбайт 18,5 Гбайт 1.81 PGDATA/pg_subtrans8 Гбайт 16 Гбайт 2 -
Ожидается большее потребление CPU/RAM в связи с вычислением 8-байтных номеров транзакций и их хранением.
-
Скрипт для оценки увеличения размера WAL и файлов данных:
Скрипт
psql -c 'CREATE TABLE phonebook(
id SERIAL PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
phone INT NOT NULL);'
echo 'INSERT INTO phonebook (name, phone) VALUES (random(), random());' > insert.sql
pgbench -j 8 -c 8 -f insert.sql -t 100000 postgres
psql -c "vacuum phonebook;"
psql -c "select relpages, reltuples from pg_class where relname = 'phonebook';"
pg_waldump -p /opt/pgdata/pg_wal/ $(ls /opt/pgdata/pg_wal | grep 00000001 | head -n1 | tr '\n' ' ') \
$(ls -r /opt/pgdata/pg_wal | grep 00000001 | head -n1 | tr '\n' ' ') | \
perl -e 'while(<>) { $_ =~ m#len \(rec/tot\):\s*(\d+)/\s*(\d+),#; $rec += $1; $tot += $2; $count++; } $rec /= $count; $tot /= $count; print "rec: $rec, tot: $tot\n";'Результат оценки:
XID32 | XID64 | Во сколько раз больше размер записей WAL и страниц файлов данных | |
|---|---|---|---|
Отчет | | | – |
WAL |
|
|
|
Число страниц в файлах данных | | | 1.018 (1.8%) |
- Затраты CPU/RAM на переупаковку страниц после процесса обновления.
Ограничения
Функциональность имеет следующие ограничения:
-
Процедура
vacuum freezeвсе еще необходима для удаления лишних сегментов CLOG (состояний транзакций) в директорииPGDATA/pg_xact, а также сегментов со смещениями мультитранзакций (offsets) и данными о членах мультитранзакций (members) в директорииPGDATA/pg_multixact. -
На одной странице, которая никогда не очищалась, не могут быть размещены данные, зафиксированные транзакциями, отстоящими друг от друга более чем на 4 млрд (), то есть должно выполняться условие:
Где:
min(t_xmin)– минимальное значениеt_xminсреди всех кортежей на странице;max(t_xmin)– максимальное (то же условие справедливо и дляt_xmax).
Невыполнение этого условия крайне маловероятно, поскольку для этого требуется принимать специальные меры: отключить
autovacuum, использовать такой профиль нагрузки, чтобы в страницу записывалась сначала одна транзакция, потом через 4 млрд транзакций другая. -
После обновления требуется перестроение индексов GIN и GiST, хранящих в страницах идентификаторы транзакций, а также других нестандартных индексов, о которых в общем случае неизвестно, хранятся ли идентификаторы транзакций в страницах или нет.
-
В
pg_upgradeрекомендуется мигрировать файлы данных путем копирования или клонирования (copy-on-write) во избежание повреждения данных в обновляемой БД из-за непредвиденных обстоятельств.