F.37. pg_archive#
F.37. pg_archive #
pg_archive - это расширение для автоматического архивирования исторических данных из секционированных таблиц путем преобразования секций в методы хранения, которые более подходят для огромных объемов холодных, только для чтения или в основном для чтения данных по сравнению с обычными таблицами PostgreSQL. В настоящее время единственным поддерживаемым архивным хранилищем является колонный метод доступа, поддерживаемый проектом Hydra, но в будущем могут быть добавлены и другие методы.
Код в общих чертах основан на отличном проекте pg_partman.
Автоматическое обслуживание для архивирования разделов на основе предоставленных пользователем
политик реализовано с помощью фонового рабочего процесса, который периодически
выполняет хранимую процедуру pg_archive_run_maintenance_proc().
Процедура проверяет разделенные таблицы, управляемые pg_archive, и преобразует разделы, содержащие данные старше
временного интервала, указанного в политике для каждой таблицы.
pg_archive_run_maintenance_proc() также может быть
вызвана вручную пользователем, когда требуется незапланированное обслуживание.
F.37.1. Установка #
Требования:
F.37.1.2. Настройка #
Фоновый рабочий процесс должен быть загружен при запуске базы данных путем добавления
библиотеки в shared_preload_libraries в
postgresql.conf
shared_preload_libraries = 'pg_archive_bgw' # (change requires a restart)
Другие GUC, которые должны быть настроены перед использованием расширения,
это interval, который представляет собой временной интервал в
секундах между запусками обслуживания фоновым процессом,
dbname, который является CSV строкой базы(баз) данных для
обслуживания, и role, которая является ролью, используемой
рабочим процессом: Вот пример:
pg_archive_bgw.interval = 3600 pg_archive_bgw.role = 'alex' pg_archive_bgw.dbname = 'mydb'
Роль должна иметь разрешения на выполнение
pg_archive_run_maintenance_proc().
Установка расширения после запуска сервера с необходимыми настроенными параметрами GUC:
CREATE SCHEMA archive; CREATE EXTENSION pg_archive SCHEMA archive;
F.37.2. Обновление #
ALTER EXTENSION pg_archive UPDATE TO '<latest version>';
F.37.3. Использование #
Разделенные таблицы могут быть настроены для управления с помощью pg_archive
с функцией pg_archive_manage().
Этот и последующие примеры в этом разделе предполагают, что pg_archive
установлен в схеме archive, а
таблицы находятся в схеме monitoring:
SELECT archive.pg_archive_manage('monitoring.metrics', 'metric_timestamp', '1 year');
pg_archive_manage
-------------------
t
(1 row)
Вышеуказанный вызов добавляет запись в таблицу
archive.pg_archive_config, которая позже будет
использована pg_archive_run_maintenance_proc() для
архивирования и, при необходимости, отсоединения разделов с данными старше 1
года в таблице metrics в
схеме monitoring на основе
значения metrics_timestamp.
Когда таблица становится управляемой pg_archive, её разделы будут
проверены и, возможно, архивированы при следующем запланированном вызове
pg_archive_run_maintenance_proc() фоновым
рабочим процессом, который по умолчанию настроен на запуск каждые 3600 секунд. В качестве альтернативы, вы можете вызвать
pg_archive_run_maintenance_proc() вручную:
CALL archive.pg_archive_run_maintenance_proc();
F.37.3.1. Примеры #
Сначала создайте расширение. Оно требует, чтобы
pg_columnar также был установлен, поэтому используйте
CASCADE.
CREATE EXTENSION pg_archive CASCADE;
После этого вы можете захотеть включить фоновый рабочий процесс для архивирования таблиц в фоновом режиме. Это требует изменений в файле конфигурации.
shared_preload_libraries = 'pg_archive_bgw' pg_archive_bgw.dbname = 'postgres' pg_archive_bgw.role = 'postgres' pg_archive_bgw.interval = 3600
Изменения:
shared_preload_libraries- фоновый рабочий процесс должен быть загружен при запуске сервера для регистрацииpg_archive_bgw.dbname- установлено вpostgresкак база данных по умолчаниюрольиинтервал- это значения по умолчанию, но вы можете их изменитьзапустите как
postgresпользователь (в производственной среде создайте отдельную роль для фонового рабочего процесса, не суперпользователь)запускать каждый час (3600 секунд)
Далее следуют дополнительные примеры. Все операции выполняются в
postgres базе данных и
public схеме. После каждого примера, данная
таблица должна быть зарегистрирована в pg_archive для дальнейшего архивирования.
Но если вы хотите, чтобы обслуживание выполнялось немедленно, выполните процедуру:
CALL pg_archive_run_maintenance_proc();
Или, вы можете захотеть принудительно преобразовать раздел. Это можно сделать с помощью другой процедуры (заметьте: она принимает имя таблицы раздела - не родителя):
CALL pg_archive_convert_partition_proc('public.partition_tbl_name');
Чтобы проверить, что таблицы архивированы, вы можете выполнить этот запрос:
SELECT c.relname, am.amname FROM pg_class c JOIN pg_am am ON c.relam = am.oid WHERE c.relname LIKE 'tbl_name%';
Примечание
'tbl_name%' в запросе должен быть заменен
на реальное имя таблицы. Предположим, что секционированные таблицы имеют
имя как у родительской таблицы плюс суффикс в конце.
Не стесняйтесь изменять границы разделов или максимальный возраст (параметр для
pg_archive_manage), чтобы проверить, что таблицы
преобразуются.
Таблица для измерений температуры, разделенная по временной метке измерения. Используется в основном для аналитики, поэтому архивируйте её часто - установите максимальный возраст на 1 день.
CREATE TABLE measurements(
temp numeric NOT NULL,
ts timestamp NOT NULL
) PARTITION BY RANGE(ts);
CREATE TABLE measurements_20240901
PARTITION OF measurements
FOR VALUES FROM ('2024-09-01') TO ('2024-09-02');
CREATE TABLE measurements_20240902
PARTITION OF measurements
FOR VALUES FROM ('2024-09-02') TO ('2024-09-03');
CREATE TABLE measurements_20240903
PARTITION OF measurements
FOR VALUES FROM ('2024-09-03') TO ('2024-09-04');
SELECT pg_archive_manage('public.measurements', 'ts', '1 day');
Храните бронирования клиентов в секционированной таблице. Бронирования могут быть изменены в любое время, поэтому секции разделены по месяцам.
CREATE TABLE bookings(
customer_id int NOT NULL,
book_date date NOT NULL
) PARTITION BY RANGE(book_date);
CREATE TABLE bookings_20240901
PARTITION OF bookings
FOR VALUES FROM ('2024-09-01') TO ('2024-09-02');
CREATE TABLE bookings_20240902
PARTITION OF bookings
FOR VALUES FROM ('2024-09-02') TO ('2024-09-03');
CREATE TABLE bookings_20240903
PARTITION OF bookings
FOR VALUES FROM ('2024-09-03') TO ('2024-09-04');
SELECT pg_archive_manage('public.bookings', 'book_date', '1 year');
Используйте секционированную таблицу для хранения журналов микросервисов. Метки времени журналов предоставляются в виде UNIX-метки времени (в секундах).
CREATE TABLE logs(
message text NOT NULL,
service int NOT NULL,
ts numeric NOT NULL
) PARTITION BY RANGE(ts);
CREATE TABLE logs_202409
PARTITION OF logs
FOR VALUES FROM (1725148800) TO (1727740800);
CREATE TABLE logs_202410
PARTITION OF logs
FOR VALUES FROM (1727740800) TO (1730419200);
CREATE TABLE logs_202411
PARTITION OF logs
FOR VALUES FROM (1730419200) TO (1733011200);
SELECT pg_archive_manage('public.logs', 'ts', '1 month', p_epoch := 'seconds');
F.37.4. Функции, Процедуры и Таблицы #
Ниже приведено описание доступных функций, их аргументов
и столбцов в таблице pg_archive_config:
F.37.4.1. pg_archive_manage() #
CREATE FUNCTION @extschema@.pg_archive_manage(
p_parent_table text
, p_control text
, p_max_age text
, p_type text DEFAULT 'range'
, p_epoch text DEFAULT 'none'
, p_automatic_maintenance boolean DEFAULT true
)
Функция регистрирует таблицу разделов для управления pg_archive.
p_parent_tableсуществующая секционированная таблица. Должна быть с указанием схемы, даже если находится в публичной схеме
p_controlимя столбца, на основе которого будет производиться секционирование. Должно быть либо временного, либо целочисленного типа.
p_max_ageлибо временной интервал в формате типа PostgreSQL
INTERVAL, либо целое значение, в зависимости от типа разбиения. Независимо от используемого типа разбиения, это значение должно быть указано как текст.
p_typeтип разбиения, используемый таблицей. В настоящее время поддерживаются только range и list. См. параметр
p_max_ageдля особых условий, связанных с типом.
p_epochсообщает
pg_archive, что управляющий столбец является целочисленным типом, но фактически представляет значение времени эпохи. Допустимые значения для этой опции:'seconds','milliseconds','nanoseconds'и'none'. Значение по умолчанию —'none'. В дополнение к обычному индексу на управляющем столбце, обязательно создайте функциональный, основанный на времени индекс на управляющем столбце(to_timestamp(controlcolumn)), чтобы это работало эффективно.
p_automatic_maintenanceуказывает, управляется ли обслуживание автоматически, когда вызывается
pg_archive_run_maintenance_proc()без параметра таблицы или фоновым рабочим процессом. По умолчаниюtrue. Когда установлено вfalse,pg_archive_run_maintenance_proc()все еще может быть вызвана для отдельного набора разделов, передавая его в качестве параметра функции.
F.37.4.2. pg_archive_convert_partition() #
CREATE PROCEDURE @extschema@.pg_archive_convert_partition_proc(
p_partition text
, p_access_method text DEFAULT 'columnar'
, p_keep_indexes boolean DEFAULT true
, p_reattach boolean DEFAULT false
)
Функция может быть полезна, когда отдельный раздел необходимо
архивировать вручную. Обратите внимание, что вам нужно вызвать
pg_archive_manage() для соответствующей
родительской таблицы, прежде чем ее разделы могут быть переданы в
pg_archive_convert_partition().
p_partitionспецификация раздела в формате
schema.name.
p_access_methodметод доступа для использования архивированной таблицы. В настоящее время
columnar(по умолчанию) является единственным поддерживаемым методом.
p_keep_indexesлогическое значение, указывающее, следует ли сохранять индексы в архивированной таблице
по умолчанию
true
p_reattachлогическое значение, указывающее, следует ли присоединить архивированную таблицу обратно к родительской таблице
по умолчанию
true
F.37.4.3. pg_archive_config #
CREATE TABLE @extschema@.pg_archive_config (
parent_table text NOT NULL
, control text NOT NULL
, partition_type text NOT NULL
, automatic_maintenance boolean NOT NULL DEFAULT true
, max_age text NOT NULL
, new_schema text
, keep_indexes boolean NOT NULL DEFAULT true
, reattach boolean NOT NULL DEFAULT true
, access_method text NOT NULL DEFAULT 'columnar'
, epoch text NOT NULL DEFAULT 'none'
, maintenance_order int
, keep_publication boolean NOT NULL DEFAULT false
, maintenance_last_run timestamptz
, CONSTRAINT pg_archive_config_parent_table_pkey PRIMARY KEY (parent_table)
);
parent_tableродительская таблица набора разделов для управления
controlстолбец, используемый в качестве контроля для ограничений разделения. Должен быть столбцом на основе времени или целым числом.
partition_typeтип разбиения. Должен быть одним из типов, упомянутых выше в документации
pg_archive_manage().
automatic_maintenanceфлаг, указывающий, управляется ли обслуживание автоматически, когда
pg_archive_run_maintenance_proc()вызывается без параметра таблицы или фоновым рабочим процессом.По умолчанию
true.Когда установлено значение
false,pg_archive_run_maintenance_proc()все еще может быть вызвана для отдельного раздела, передавая его в качестве параметра функции.
max_agetext type value, который определяет, насколько старыми могут быть данные в дочернем разделе, прежде чем раздел будет архивирован.
new_schemaсхема для перемещения архивированных разделов в рамках процесса архивирования.
NULL(по умолчанию) означает, что разделы не изменяют свою схему после архивирования.
keep_indexesлогическое значение, указывающее, следует ли удалять индексы для архивированных таблиц.
По умолчанию
true. Установка вfalseозначает, что pg_archive не будет пытаться воссоздать какие-либо индексы на архивированной таблице. Обратите внимание, что если таблица настроена на повторное присоединение архивированных разделов (см.reattachниже), PostgreSQL может автоматически воссоздать индексы, унаследованные от родительской таблицы. См. документацию PostgreSQL дляALTER TABLE ATTACH PARTITIONдля получения дополнительной информации.
reattachлогическое значение, указывающее, должны ли разделы оставаться прикрепленными к родительской таблице после преобразования. Установка его в «false» означает, что разделы будут продолжать существовать как отдельные таблицы после архивации, т.е. будут отсоединены от родительской таблицы.
по умолчанию
true
access_methodметод доступа для использования при преобразовании разделов во время архивирования
значение по умолчанию и единственное в настоящее время поддерживаемое значение -
columnar
epochуказывает, что таблица разделена по времени с использованием целочисленного значения эпохи вместо метки времени. См. описание соответствующего аргумента в
pg_archive_manage()функции для получения дополнительной информации.по умолчанию
'none'.
maintenance_orderцелочисленное значение, определяющее порядок выполнения обслуживания наборов разделов. Наборы будут выполняться в порядке возрастания числового значения.
значение по умолчанию
NULL. Все наборы разделов, установленные в NULL, будут выполняться после наборов разделов с определенным значением. Наборы разделовNULLвыполняются в неопределенном порядке.для наборов с подчастичными разделами дочерние таблицы по умолчанию наследуют порядок своих родительских таблиц. Дочерние родительские таблицы будут выполняться в логическом порядке, когда будет выполняться обслуживание их родительской таблицы, если оставить значение по умолчанию.
keep_publicationопределяет, следует ли удалять архивированные разделы из любых публикаций, членами которых они могут быть.
по умолчанию
false, что означает, что архивированные разделы удаляются из их публикаций.
maintenance_last_runвременная метка последнего успешного запуска обслуживания для этого набора разделов. Может быть полезно в качестве метрики мониторинга для обеспечения правильной работы обслуживания разделов.
F.37.5. Ограничения в использовании #
В рамках процедуры архивирования pg_archive должен скопировать данные раздела в новую таблицу, а затем обменять существующий раздел на новую архивированную версию (если только reattach не настроен на false для этой таблицы). Поскольку ALTER TABLE ... EXCHANGE PARTITION в настоящее время не поддерживается PostgreSQL, это сводится либо к DROP TABLE, либо к ALTER TABLE DETACH PARTITION, за которым следует ALTER TABLE ATTACH PARTITION.
Оба DROP TABLE для раздела и
DETACH PARTITION берут
ACCESS EXCLUSIVE блокировку на родительской таблице, что
проблематично для загруженных таблиц. Хотя в PostgreSQL 14
была введена команда DETACH PARTITION CONCURRENTLY для
решения этой конкретной проблемы, эта функциональность недоступна
для расширений, потому что
ALTER TABLE DETACH PARTITION CONCURRENTLY должна
быть командой верхнего уровня и не может использоваться в хранимых процедурах.
См.
это
обсуждение на pgsql-general для получения дополнительной информации.
В результате pg_archive в настоящее время использует
DROP TABLE для отсоединения раздела как единственный
жизнеспособный вариант. Мы осознаем проблемы, которые это может вызвать для загруженных,
часто изменяющихся таблиц, и ищем возможные обходные пути.