TimescaleDB — расширение PostgreSQL, которое превращает обычную таблицу с метриками в гипертаблицу, разбитую на чанки по времени. Запросы продолжают работать на SQL, транзакции и резервное копирование остаются родными для PostgreSQL, но появляются отсечение чанков по времени, колоночное сжатие, непрерывные агрегаты и политики хранения. Для домашнего мониторинга этого часто достаточно.

Зачем расширение обычной PostgreSQL

Гипертаблица физически состоит из набора чанков. Планировщик отбрасывает чанки вне диапазона WHERE, поэтому выборка за час не читает годы данных. Старые чанки сжимаются и удаляются, агрегаты пересчитываются по расписанию.

  • вставка идёт пакетами, а не по одной строке;
  • непрерывные агрегаты хранят результат, а не пересчитывают его на каждый запрос;
  • сжатие уменьшает объём, но требует порядка в ключах.

Расширение привязано к версии PostgreSQL.

Установка

Ставьте PostgreSQL из репозитория PGDG, а TimescaleDB — из репозитория Timescale. Смешивать пакеты из дистрибутива и PGDG не стоит: расширение собирается под конкретную версию сервера.

sudo apt install gnupg postgresql-common apt-transport-https lsb-release wget
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" | sudo tee /etc/apt/sources.list.d/timescaledb.list
wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/timescaledb.gpg
sudo apt update
sudo apt install timescaledb-2-postgresql-18 postgresql-client-18
sudo timescaledb-tune --quiet --yes
sudo systemctl restart postgresql

timescaledb-tune прописывает shared_preload_libraries = 'timescaledb' и подбирает параметры памяти. Без предзагрузки библиотеки CREATE EXTENSION завершится ошибкой. Проверьте версию и включите расширение:

sudo -u postgres psql -d metrics
CREATE EXTENSION IF NOT EXISTS timescaledb;
SELECT extversion FROM pg_extension WHERE extname = 'timescaledb';
SHOW shared_preload_libraries;

Гипертаблица для метрик

Начните с обычной таблицы: время, измерения и значение. Интервал чанка выбирайте так, чтобы активный чанк и индексы помещались в память; для метрик раз в 10 секунд подходит один день.

CREATE TABLE metrics (
  ts     timestamptz      NOT NULL,
  host   text             NOT NULL,
  metric text             NOT NULL,
  value  double precision NOT NULL
);

SELECT create_hypertable(
  'metrics',
  by_range('ts', INTERVAL '1 day')
);

CREATE INDEX ON metrics (host, metric, ts DESC);

by_range появился в TimescaleDB 2.13; в старых версиях используют create_hypertable('metrics', 'ts', chunk_time_interval => INTERVAL '1 day'). Индекс по (host, metric, ts DESC) обслуживает запрос «последние значения по хосту и метрике».

Запись данных

Главная ошибка — вставлять строки по одной в отдельных транзакциях. PostgreSQL накладнее всего на коммитах, а TimescaleDB добавляет работу с чанками.

\copy metrics FROM '/tmp/metrics.csv' WITH (FORMAT csv, HEADER true)

INSERT INTO metrics (ts, host, metric, value)
SELECT g, 'db-1', 'cpu', random() * 100
FROM generate_series(
  now() - INTERVAL '1 hour',
  now(),
  INTERVAL '10 seconds'
) AS g;

Для потока из приложения используйте один INSERT на сотни строк. Если запись идёт чаще раза в секунду на хост, проверьте диск: iostat -x 1 и pg_stat_io.

Непрерывные агрегаты

Непрерывный агрегат — материализованное представление, которое TimescaleDB обновляет по политике. Он хранит посчитанные значения, поэтому дашборд не сканирует сырые данные.

CREATE MATERIALIZED VIEW metrics_hourly
WITH (timescaledb.continuous) AS
SELECT time_bucket('1 hour', ts) AS bucket,
       host,
       metric,
       avg(value) AS avg_value
FROM metrics
GROUP BY bucket, host, metric
WITH NO DATA;

SELECT add_continuous_aggregate_policy('metrics_hourly',
  start_offset      => INTERVAL '3 days',
  end_offset        => INTERVAL '1 hour',
  schedule_interval => INTERVAL '30 minutes'
);

CALL refresh_continuous_aggregate('metrics_hourly', NULL, now() - INTERVAL '1 hour');

WITH NO DATA создаёт пустое представление; первый вызов refresh_continuous_aggregate наполняет его. end_offset защищает от пересчёта незакрытого окна. Если нужны свежие строки без ожидания политики, включите timescaledb.materialized_only = false.

Сжатие и хранение

Сжатие включается для таблицы и применяется к чанкам по политике. Ключ сегментирования — измерения, по которым чаще фильтруют; ключ сортировки — время.

ALTER TABLE metrics SET (
  timescaledb.compress,
  timescaledb.compress_segmentby = 'host, metric',
  timescaledb.compress_orderby   = 'ts DESC'
);

SELECT add_compression_policy('metrics', INTERVAL '7 days');
SELECT add_retention_policy('metrics', INTERVAL '180 days');
SELECT add_retention_policy('metrics_hourly', INTERVAL '2 years');

Сжатый чанк нельзя обновлять обычным UPDATE; для правок его распаковывают или меняют только «горячие» чанки. Политика хранения удаляет целые чанки, поэтому она необратима.

Запросы и диагностика

time_bucket группирует по интервалу, time_bucket_gapfill добавляет пропущенные окна — пауза в данных не должна выглядеть как ноль.

SELECT time_bucket_gapfill('5 minutes', ts) AS bucket,
       host,
       avg(value) AS avg_value
FROM metrics
WHERE ts > now() - INTERVAL '6 hours'
  AND host = 'db-1'
  AND metric = 'cpu'
GROUP BY bucket, host;
SELECT * FROM timescaledb_information.hypertables;
SELECT * FROM timescaledb_information.job_stats;
SELECT * FROM hypertable_detailed_size('metrics');
SELECT * FROM chunk_compression_stats('metrics');

Перед оптимизацией снимите план: EXPLAIN (ANALYZE, BUFFERS) должен показывать сканирование одного-двух чанков. Если чанков слишком много, увеличьте интервал; если запрос медленный, проверьте порядок колонок в индексе.

Резервное копирование и обновление

Логический дамп переносит данные и чанки, но требует расширения той же версии. Для физического восстановления вызовите служебные функции до и после восстановления.

pg_dump -Fc -d metrics -f /var/backups/metrics.dump
pg_restore -d metrics_restore /var/backups/metrics.dump

psql -d metrics -c "SELECT timescaledb_pre_restore();"
# физическое восстановление каталога данных
psql -d metrics -c "SELECT timescaledb_post_restore();"

ALTER EXTENSION timescaledb UPDATE;

Перед обновлением пакета прочитайте примечания к выпуску. Понижение версии расширения не поддерживается, поэтому сначала обновите тестовый стенд.

Чек-лист эксплуатации

  • shared_preload_libraries содержит timescaledb, версии совпадают;
  • интервал чанка соответствует объёму записи и памяти;
  • политики сжатия и хранения включены и видны в job_stats;
  • резервная копия проверена восстановлением.

Итог

TimescaleDB — прагматичный способ хранить временные ряды в PostgreSQL, не заводя вторую СУБД. Гипертаблица ускоряет выборки за счёт чанков, непрерывные агрегаты снимают нагрузку с дашбордов, а сжатие и retention позволяют годами держать историю на одном сервере.

Начинайте с одной таблицы и одной политики, измеряйте размер чанков и планы запросов. Расширение не исправит плохую схему: если ключи сжатия и индексы выбраны наугад, база станет только сложнее.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте