Привет, Хабр! Мой коллега Артем уже описал архитектуру управления жизненным циклом данных в этой статье, а я хочу рассказать о применении ILM с практической стороны.
Расширение pg_ilm управляет размещением данных по уровням хранения в зависимости от их активности. Оно не автоматизирует действия, а помогает администратору принимать решения: отслеживает статистику обращений к таблицам и партициям, определяет «холодные» данные и выдаёт рекомендации по перемещению на более дешёвые носители или сжатию. В отличие от самодельных скриптов, ориентированных на дату создания, pg_ilm учитывает реальную частоту доступа за настраиваемый период. Решение по каждой рекомендации остаётся за DBA.
На чём же основаны рекомендации? Система анализирует три группы факторов:
-
Физическое состояние хранения — где и как лежат данные сейчас (табличное пространство и метод доступа).
-
Уровень активности — насколько интенсивно идёт запись в таблицу.
-
Настроенные правила архивирования — заданные администратором условия перехода.
Цикл управления данными разделён на три независимых этапа:
-
Политика жизненного цикла (rules) — администратор задаёт условия перемещения и целевой метод доступа. Правила хранятся в таблице
ilm.archive_rules, изменения применяются без остановки СУБД. -
Вычисление перехода (recommendation) — на основе статистики активности и правил система формирует список действий для каждой таблицы или партиции. Рекомендации доступны для просмотра до момента применения.
-
Физическое исполнение — функция
ilm.execute_recommendations()применяет сгенерированные рекомендации. Вызов выполняется вручную, это позволяет проверить корректность правил, оценить время операций и состав затронутых объектов до фактического перемещения.
Разделение этапов гарантирует, что данные не изменяют состояние без явного подтверждения администратора. ILM не затрагивает горячие таблицы — только объекты, удовлетворяющие условиям правил.
Переход данных между состояниями зависит не только от правил, но и от физических характеристик: текущего табличного пространства, метода доступа (heap или columnar), типа объекта (таблица или партиция), а также ограничений механизмов архивирования. Поэтому pg_ilm использует не бинарную модель, а ограниченный автомат состояний, что исключает попытки выполнить технически невозможные перемещения.
Расширение pg_ilm доступно начиная с Tantor Postgres 18. Перед настройкой требуется подготовить БД: настроить сервер, создать табличные пространства для разных температурных зон и установить расширения в правильном порядке. В postgresql.conf необходимо указать библиотеки — параметр применяется после перезапуска СУБД.
shared_preload_libraries = 'pg_archive_bgw, pg_cron, pg_partman_bgw'
За что отвечают библиотеки:
-
pg_archive_bgw — фоновый процесс для операций архивирования;
-
pg_cron — планировщик заданий;
-
pg_partman_bgw — фоновое обслуживание партиций.
Модель состояний
pg_ilm использует конечный набор физических состояний хранения данных, определяемых комбинацией двух характеристик:
-
метод доступа — heap (строчное хранение) или columnar (колоночное);
-
размещение — в каком табличном пространстве лежат данные.
Основные состояния:
|
Состояние |
Access method |
Табличное пространство |
|
hot_row |
heap |
горячее (по умолчанию) |
|
warm_row |
heap |
холодное (архивное) |
|
warm_columnar |
columnar |
горячее (по умолчанию) |
|
cold_columnar |
columnar |
холодное (архивное) |
На практике администратор не обязан использовать все четыре состояния, можно выбрать только то, что соответствует вашей инфраструктуре:
-
Только сжатие без перемещения: переводите старые данные в warm_columnar, оставляя их на тех же дисках. Табличные пространства для холодных данных вам не понадобятся.
-
Только перемещение без сжатия: перекладывайте warm_row на более дешёвые носители, не меняя метод доступа.
-
Полный цикл: hot_row → warm_row → cold_columnar: и перемещение, и сжатие.
pg_ilm не пытается сразу перевести таблицу в конечное состояние, он только вычисляет следующий допустимый шаг. Поэтому правило с целевым состоянием cold_columnar может сначала дать рекомендацию warm_row, если прямой переход невозможен.
Если вы планируете использовать перемещение между табличными пространствами, понадобятся несколько табличных пространств. Если только сжатие — можно обойтись одним.
Важно понимать, что pg_ilm никогда не перепрыгивает через состояния. Если целевое состояние — cold_columnar, система сначала переведёт таблицу в warm_row (переместит в холодное табличное пространство, но оставит метод доступа heap), и только потом — в cold_columnar (сменит метод доступа на columnar). Почему так? Потому что pg_ilm использует безопасный пошаговый подход, а прямой переход из hot_row в cold_columnar хоть и технически возможен, но постепенный переход позволяет минимизировать блокировки, сохранять контроль на каждом этапе и избегать ошибок при больших объёмах данных.
ILM для обычной таблицы (regular_table)
Работа ILM с обычными (несекционированными) таблицами предполагает, что правило применяется ко всей таблице целиком. Нельзя охладить часть строк, а только всю таблицу. Поэтому обычные таблицы подходят для справочников или небольших таблиц, которые полностью переходят в холодное состояние, а для массовых стоит использовать секционирование (об этом ниже).
Подготовка табличного пространства (опционально). Для полного цикла с перемещением между носителями и изменением метода доступа на columnar необходимо сперва создать холодное табличное пространство, предварительно создав соответствующий каталог в файловой системе.
mkdir -p /path/to/tablespace/cold_tschown postgres:postgres /path/to/tablespace/cold_tschmod 700 /path/to/tablespace/cold_ts
Затем в базе данных:
CREATE TABLESPACE cold_ts LOCATION ‘/path/to/tablespace/cold_ts’;
Если нужна только конвертация в columnar без перемещения — табличное пространство не требуется.
Также необходимо создать схемы и расширения:
CREATE SCHEMA IF NOT EXISTS partman;CREATE SCHEMA IF NOT EXISTS archive;CREATE EXTENSION IF NOT EXISTS pg_cron CASCADE;CREATE EXTENSION IF NOT EXISTS pg_partman SCHEMA partman;CREATE EXTENSION IF NOT EXISTS pg_archive SCHEMA archive CASCADE;CREATE EXTENSION IF NOT EXISTS pg_ilm CASCADE;
Создание тестовой таблицы:
CREATE SCHEMA IF NOT EXISTS test; CREATE TABLE test.sensors ( id SERIAL, device_id INTEGER NOT NULL, sensor_type TEXT, value NUMERIC(10, 2));
Заполнение тестовыми данными. ILM оценивает активность таблицы по реальным операциям записи, а не по датам в данных. Поэтому просто наполним таблицу любыми данными:
INSERT INTO test.sensors (device_id, sensor_type, value)SELECT (random() * 100)::INT, (ARRAY['temperature', 'humidity', 'pressure'])[ceil(random() * 3)], random() * 100FROM generate_series(1, 100000000);Размер таблицы больше 5GB.SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_sizeFROM pg_tablesWHERE tablename = 'sensors'; schemaname | tablename | total_size------------+-----------+------------ test | sensors | 5257 MB
Создание правила ILM. Правило говорит: через 10 минут неактивности таблица становится кандидатом на переход в состояние cold_columnar, через 20 минут — появится рекомендация.
SELECT ilm.archive_rule_upsert( p_target_table => 'test.sensors', p_target_kind => 'regular_table', p_target_state => 'cold_columnar', p_idle_threshold => '20 minutes', p_cold_after => '10 minutes', p_cold_tablespace => 'cold_ts', p_cold_access_method => 'columnar', p_keep_indexes => true);
⚠️ Для теста используется 10 минут. В реальной эксплуатации указывайте столько, сколько подходит вашей архитектуре.
Сбор статистики может быть настроен через pg_cron по расписанию, также можно выполнить вручную:
SELECT ilm.collect_stats_snapshot();
Просмотр рекомендаций. Возможные сценарии:
|
recommendation_status |
current_state |
recommended_next_state |
Что означает? |
|
skip |
любое |
— |
Таблица ещё активна |
|
recommend |
hot_row |
warm_row |
Первый шаг: перемещение в cold_ts |
|
recommend |
warm_row |
cold_columnar |
Второй шаг: переход в columnar |
Пока не пройдет время, заданное на предыдущем этапе создания правила в p_idle_threshold и p_cold_after, будет видно текущее состояние таблицы и отсутствие рекомендаций:
SELECT *FROM ilm.recommend_archive_actions(NULL, now(), FALSE)WHERE target_table = 'test.sensors'\gx-[ RECORD 1 ]------------+------------------------------------------------rule_id | 1target_table | test.sensorsresolved_target_kind | regular_tablecurrent_state | hot_rowrecommended_next_state |recommendation_status | skiprecommendation_reason | table does not satisfy idle/size thresholds yetprepared_call_sql |blocking_constraints |query_compatibility_risk | lowaccess_risk | lowrestore_risk | low
Спустя заданное время появится рекомендация и причина ее появления наряду с SQL-запросом, который эту рекомендацию выполнит.
SELECT *FROM ilm.recommend_archive_actions(NULL, now(), FALSE)WHERE target_table = 'test.sensors'\gx-[ RECORD 1 ]------------+--------------------------------------------------------------------------------------------------------rule_id | 1target_table | test.testresolved_target_kind | regular_tablecurrent_state | hot_rowrecommended_next_state | warm_rowrecommendation_status | recommendrecommendation_reason | row-oriented cold placement is recommendedprepared_call_sql | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.sensors'::regclass, p_dry_run := FALSE);blocking_constraints |query_compatibility_risk | lowaccess_risk | lowrestore_risk | low
В данном кейсе появляется рекомендация переноса в холодное табличное пространство без изменения метода доступа.
Выполнение первого шага: hot_row → warm_row осуществляется с помощью выполнения prepared_call_sql. Рекомендация сформирована, и теперь нужно её выполнить, функция ilm.execute_recommendations() как раз для этого и предназначена. Но прежде чем что-то менять, важно убедиться, что всё пройдёт гладко. Для этого предусмотрен параметр p_dry_run — если установить его в TRUE, система покажет, что именно будет сделано, но ничего реально не выполнит:
SELECT * FROM ilm.execute_recommendations( p_target_table := 'test.sensors'::regclass, p_dry_run := TRUE);
Это безопасный способ посмотреть, какая таблица или партиция будет затронута, какая SQL-команда будет выполнена, и оценить возможные риски. Когда убедимся, что всё корректно, выполняем с p_dry_run := FALSE:
SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.sensors'::regclass, p_dry_run := FALSE);
Что произошло:
-
таблица переместилась в cold_ts, таким образом более 5GB было освобождено на дорогом носителе
-
метод доступа остался heap
Проверяем:
SELECT relname, (SELECT spcname FROM pg_tablespace WHERE oid = reltablespace) AS tablespace, CASE relam WHEN 2 THEN 'heap' ELSE 'other' END AS access_methodFROM pg_classWHERE relname = 'sensors'; relname | tablespace | access_method---------+------------+--------------- sensors | cold_ts | heap
Поскольку мы указали в правиле p_target_state = cold_columnar, то после того как таблица оказалась в cold_ts, ILM предложит следующий шаг: warm_row → cold_columnar. Снова смотрим рекомендации:
SELECT * FROM ilm.recommend_archive_actions(NULL, now(), FALSE)WHERE target_table = 'test.sensors'\gx-[ RECORD 1 ]------------+--------------------------------------------------------------------------------------------------------rule_id | 1target_table | test.sensorsresolved_target_kind | regular_tablecurrent_state | warm_rowrecommended_next_state | cold_columnarrecommendation_status | recommendrecommendation_reason | columnar cold placement is recommended; execution may recreate directly in cold tablespaceprepared_call_sql | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.sensors'::regclass, p_dry_run := FALSE);blocking_constraints |query_compatibility_risk | lowaccess_risk | lowrestore_risk | high
Теперь current_state = ‘warm_row’, recommended_next_state = ‘cold_columnar’, то есть на данном этапе уже рекомендуется изменить метод доступа на columnar в холодном табличном пространстве.
Выполняем:
SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.sensors'::regclass, p_dry_run := FALSE);
Проверка финального состояния:
SELECT c.relname, (SELECT spcname FROM pg_tablespace WHERE oid = c.reltablespace) AS tablespace, a.amname AS access_methodFROM pg_class cLEFT JOIN pg_am a ON c.relam = a.oidWHERE c.relname = 'sensors'; relname | tablespace | access_method---------+------------+--------------- sensors | cold_ts | columnarА размер таблицы теперь 760MB.SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_sizeFROM pg_tablesWHERE tablename = 'sensors'; schemaname | tablename | total_size------------+-----------+------------ test | sensors | 760 MB
Видим, что таблица находится в целевом табличном пространстве и с целевым методом доступа, которые были заявлены на этапе создания правила ILM. А ее объем почти в 7 раз меньше. Таким образом мы не только переложили таблицу на более дешевый диск, но она теперь и на более дешевом носителе занимает намного меньше места.
Альтернативный вариант — сжатие без перемещения. Если перемещение между дисками не нужно, используйте целевое состояние warm_columnar:
SELECT ilm.archive_rule_upsert( p_target_table => 'test.sensors', p_target_kind => 'regular_table', p_target_state => 'warm_columnar', -- только сжатие p_idle_threshold => '20 minutes', p_cold_after => '10 minutes', p_cold_access_method => 'columnar', p_keep_indexes => true);
В этом случае переход один: hot_row → warm_columnar. Табличное пространство не меняется.
Итак, мы рассмотрели обычную таблицу, она отлично подходит для небольших справочников или объектов, которые переезжают целиком, но есть ограничение: правило применяется ко всей таблице целиком. Часть данных «охладить» нельзя, только всё сразу. Но если ваша таблица весит терабайт и каждый день растёт, то для таких сценариев одного правила на всю таблицу недостаточно, нужно управлять по частям. Здесь на помощь приходит секционирование: ILM получает возможность управлять каждой партицией отдельно. Можно спокойно вставлять новые данные в горячие партиции, пока старые уже переезжают в архив — без простоев и блокировок на весь объём.
ILM для случаев с секционированием
Фундаментально ничего не меняется: так же настраиваются правила, собирается статистика, появляются рекомендации, просто теперь ILM будет управлять не всей таблицей, а каждой партицией по отдельности.
Разберём на примере: создадим таблицу с партициями по 5 минут, настроим ILM, добавим данные и проследим, как старые партиции сначала переезжают в холодное табличное пространство, а затем изменяют метод доступа на columnar.
CREATE TABLE test.events ( id BIGSERIAL, event_time TIMESTAMPTZ NOT NULL, device_id INTEGER NOT NULL, sensor_value NUMERIC(10, 2)) PARTITION BY RANGE (event_time); SELECT partman.create_parent( p_parent_table => 'test.events', p_control => 'event_time', p_interval => '5 minutes', p_premake => 120, p_type => 'range');
При создании правила для секционированной таблицы (target_kind = ‘partitioned_parent’) параметры p_control_column и p_max_age обязательны. Без них ограничение-проверка в таблице ilm.archive_rules не позволит вставить запись.
SELECT conname, pg_get_constraintdef(oid)FROM pg_constraintWHERE conname = 'archive_rules_check'; conname | pg_get_constraintdef ---------------------+---------------------------------------------------------------------------------------------------------------------------------------- archive_rules_check | CHECK (((target_kind = ANY (ARRAY['auto'::text, 'regular_table'::text])) OR ((control_column IS NOT NULL) AND (max_age IS NOT NULL))))
Настроим правила для партицированной таблицы:
SELECT ilm.archive_rule_upsert( p_target_table => 'test.events', p_target_kind => 'partitioned_parent', p_target_state => 'cold_columnar', p_control_column => 'event_time', p_max_age => '60 minutes', p_cold_after => '10 minutes', p_idle_threshold => '10 minutes', p_min_age => '00:00:00', p_cold_tablespace => 'cold_ts', p_cold_access_method => 'columnar', p_keep_indexes => true, p_enabled => true);
Соберем статистику:
SELECT ilm.collect_stats_snapshot();
Для тестового примера была настроена вставка каждые 5 минут в новую партицию, а спустя 10 минут неактивности появляется рекомендация на новую партицию.
Проверим рекомендации:
SELECT * FROM ilm.recommend_archive_actions(NULL, NOW(), FALSE)where target_table like '%events_p%' ORDER BY target_table DESC; rule_id | target_table | resolved_target_kind | current_state | recommended_next_state | recommendation_status | recommendation_reason | prepared_call_sql | blocking_constraints | query_compatibility_risk | access_risk | restore_risk---------+------------------------------+----------------------+---------------+------------------------+-----------------------+----------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+----------------------+--------------------------+-------------+-------------- 7 | test.events_p20260608_135500 | partition_leaf | hot_row | warm_row | recommend | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.events_p20260608_135500'::regclass, p_dry_run := FALSE); | | low | low | medium 7 | test.events_p20260608_135000 | partition_leaf | hot_row | warm_row | recommend | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.events_p20260608_135000'::regclass, p_dry_run := FALSE); | | low | low | medium
Спустя пять минут появляется рекомендация на новую партицию:
SELECT * FROM ilm.recommend_archive_actions(NULL, NOW(), FALSE)where target_table like '%events_p%' ORDER BY target_table DESC; rule_id | target_table | resolved_target_kind | current_state | recommended_next_state | recommendation_status | recommendation_reason | prepared_call_sql | blocking_constraints | query_compatibility_risk | access_risk | restore_risk---------+------------------------------+----------------------+---------------+------------------------+-----------------------+----------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+----------------------+--------------------------+-------------+-------------- 7 | test.events_p20260608_140000 | partition_leaf | hot_row | warm_row | recommend | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.events_p20260608_140000'::regclass, p_dry_run := FALSE); | | low | low | medium 7 | test.events_p20260608_135500 | partition_leaf | hot_row | warm_row | recommend | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.events_p20260608_135500'::regclass, p_dry_run := FALSE); | | low | low | medium 7 | test.events_p20260608_135000 | partition_leaf | hot_row | warm_row | recommend | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(p_target_table := 'test.events_p20260608_135000'::regclass, p_dry_run := FALSE); | | low | low | medium
ILM последовательно добавляет рекомендации по мере того, как партиции «остывают». Это демонстрирует, что система работает в реальном времени и каждая партиция обрабатывается независимо. Если выполнить вставку в партицию events_p20260608_135000, на которую уже есть рекомендация, и собрать статистику, то рекомендация по ней исчезнет до следующего периода неактивности, который был выставлен в правиле.
Рекомендации по ней больше нет. Партиция снова стала активной, и ILM будет ждать нового периода неактивности, прежде чем снова предложить её охладить.
SELECT * FROM ilm.recommend_archive_actions(NULL, NOW(), FALSE)where target_table like '%test.events_p20260608_135000%' ORDER BY target_table DESC; rule_id | target_table | resolved_target_kind | current_state | recommended_next_state | recommendation_status | recommendation_reason | prepared_call_sql | blocking_constraints | query_compatibility_risk | access_risk | restore_risk---------+--------------+----------------------+---------------+------------------------+-----------------------+-----------------------+-------------------+----------------------+--------------------------+-------------+--------------(0 строк)
Итак, пример наглядно демонстрирует ключевые принципы работы ILM:
|
Сценарий |
Поведение ILM |
|
Партиция не получает новые данные в течение p_cold_after |
Появляется рекомендация на охлаждение |
|
В партицию снова начали писать данные |
Рекомендация исчезает до следующего периода неактивности |
|
Партиции обрабатываются независимо |
Каждая партиция живёт своей жизнью |
Еще раз подчеркну, что ILM не принимает окончательного решения за администратора. Он лишь формирует рекомендации, которые можно принять, отклонить или отложить. Это даёт полный контроль над процессом охлаждения данных.
Всегда ли можно доверять рекомендациям?
Допустим, что администратор настраивает правило для новой таблицы:
SELECT ilm.archive_rule_upsert( p_target_table => 'production.orders', p_target_kind => 'regular_table', p_target_state => 'cold_columnar', p_cold_after => '30 days', ...);
Всё верно: данные старше 30 дней должны переезжать в холодное хранилище. Но через пару дней после настройки ILM неожиданно выдаёт рекомендацию. Почему? Может быть, есть ошибка в параметре p_cold_after и указано 30 минут вместо 30 дней? Может быть, сбилась статистика или таблица действительно «остыла» намного быстрее, чем ожидалось? Чтобы ответить на эти вопросы, нужен независимый источник правды об активности данных. В pg_ilm реализован удобный способ визуальной оценки активности — Flamegraph. Это текстовая шкала, где длина строки из символов █ показывает, насколько часто таблица изменяется. Чем длиннее полоска, тем активнее идут записи. Этот инструмент не зависит от настроенных правил ILM и показывает реальную картину. Для этого используется функция flame(). Она принимает один параметр — интервал времени, за который нужно проанализировать изменения. Flamegraph сортирует результаты по убыванию активности. Это значит, что самая активная таблица всегда будет вверху списка, в нашем случае это active_demo, которая не просто попала в список, а возглавляет его. Если таблица во всей схеме самая активная, можно ли её охлаждать? Очевидно, что нет, поскольку хлаждение предназначено для данных, которые давно не менялись, а не для тех, которые изменяются чаще всех остальных.
SELECT target_table::text, current_state, recommended_next_state, recommendation_statusFROM ilm.recommend_archive_actions('test.active_demo'::regclass, NOW(), FALSE); target_table | current_state | recommended_next_state | recommendation_status------------------+---------------+------------------------+----------------------- test.active_demo | hot_row | warm_row | recommend SELECT schemaname, relname, flame, total_blocks_dirtiedFROM ilm.flame('1 hour'::interval) where schemaname = 'test' limit 10; schemaname | relname | flame | total_blocks_dirtied------------+-------------------------+----------------------+---------------------- test | active_demo | ████████████████████ | 8 test | events_p20260608_135000 | ██████████████████ | 26 test | events_p20260608_133500 | █████████████ | 11 test | events_p20260608_135500 | █████████████ | 11 test | events_p20260608_140000 | █████████████ | 11
Обратите внимание и на длину полоски flame. У таблицы active_demo она состоит из 20 символов █. Это очень много, поскольку речь не о единичной вставке или редком обновлении, а об устойчивой, постоянной активности. Таблица живёт своей жизнью: кто-то постоянно вставляет новые записи, обновляет существующие или удаляет старые. Таблица эта не просто «тёплая» или «активная», она устойчиво самая горячая из всех. ILM выдал рекомендацию на охлаждение этой таблицы. а flamegraph говорит об обратном. Кому верить?
Верить в этой ситуации нужно flamegraph, потому что он показывает реальную активность, основанную на объективной статистике изменений блоков, а рекомендация ILM — всего лишь результат вычислений на основе настроенных вами правил. Если в правиле ошибка (например, вы случайно указали cold_after = ‘1 minute’ вместо ’30 days’), ILМ добросовестно выдаст рекомендацию. Flamegraph же от правил не зависит, а смотрит только на данные. Поэтому именно он является независимым источником правды.
Итак, прежде чем выполнять рекомендацию, смотрим на объективную картину, и если замечаем расхождение — правила стоит проверить. Скорее всего там указаны слишком маленькие значения cold_after и idle_threshold. Проверим:
SELECT target_table::text, cold_after, idle_thresholdFROM ilm.archive_rulesWHERE target_table = 'test.active_demo'::regclass; target_table | cold_after | idle_threshold------------------+------------+---------------- test.active_demo | 00:30:00 | 00:30:00
Для активной таблицы такие значения не подходят. Охлаждение имеет смысл только после длительного периода неактивности (дни, недели, месяцы), а не через 30 минут. Внесем изменения:
UPDATE ilm.archive_rulesSET cold_after = '30 days', idle_threshold = '30 days'WHERE target_table = 'test.active_demo'::regclass;UPDATE 1SELECT target_table::text, cold_after, idle_thresholdFROM ilm.archive_rulesWHERE target_table = 'test.active_demo'::regclass; target_table | cold_after | idle_threshold------------------+------------+---------------- test.active_demo | 30 days | 30 days
Соберём свежую статистику и посмотрим, что изменилось. Теперь мы увидим recommendation_status = ‘skip’. Это означает, что ILM больше не рекомендует охлаждать эту таблицу.
SELECT ilm.collect_stats_snapshot(); collect_stats_snapshot------------------------ (1 строка) SELECT target_table::text, current_state, recommended_next_state, recommendation_statusFROM ilm.recommend_archive_actions('test.active_demo'::regclass, NOW(), FALSE); target_table | current_state | recommended_next_state | recommendation_status------------------+---------------+------------------------+----------------------- test.active_demo | hot_row | | skip
В заключение
ILM в Tantor Postgres 18 работает по «трёхфазной» схеме: администратор задаёт правила, система собирает статистику и выдаёт рекомендации, а вот что делать дальше — решение за администратором. В статье мы прошли все этапы: установка расширений, настройка tablespace’ов, работа с обычными и секционированными таблицами, проверка рекомендаций через Flamegraph. Главное правило — доверять, но проверять.
Что может пойти не так:
-
параметр
p_cold_afterвыставлен неправильно — ILM будет предлагать охлаждать то, что ещё активно; -
пропущен
control_columnдля секционированной таблицы — правило не создастся; -
сбор статистики отключён — рекомендаций не будет вообще.
Практический порядок внедрения:
-
Начать с небольшой тестовой таблицы, понаблюдать за рекомендациями, сверить с реальной картиной.
-
Откорректировать настройки до совпадения с ожиданиями.
-
Переходить к секционированным таблицам и рабочим объёмам.
-
Автоматизацию (через Платформу Tantor или собственные решения) внедрять только после полного понимания поведения ILM на стенде. «Из коробки» автоматического исполнения нет — именно исходя из того понимания, что администратор должен сам контролировать каждый шаг.
По сути, ILM дает стандартизированный прозрачный способ управлять жизненным циклом данных, избавляя от необходимости каждый раз изобретать велосипед с самописными скриптами. Настроили правильно — работает. Ошиблись — поправили. Всё остальное — вопрос времени и практики. Как сказал герой «Человека-паука» 2003 года: «Чем больше сила, тем больше ответственность». Вот и администратор с ILM должен подходить к его использованию осознанно и ответственно.
ссылка на оригинал статьи https://habr.com/ru/articles/1049632/