Рецепт 6. Вертикальное масштабирование Postgres со storage. Часть 1

Часть 1 истории про вертикальное масштабирование Postgres в Kubernetes: отдельный volume для WAL, временные tablespaces, разделение I/O для таблиц и индексов.
Опубликовано:

Боитесь, что Postgres «не масштабируется на запись» в одном узле? Думаете, что масштабировать его можно только горизонтально? Не торопитесь хоронить вертикальное масштабирование.

На KubeCon EU 2024 в Париже автор вместе с Gari Singh из Google Cloud делал доклад «Scaling Heights: Mastering Postgres Database Vertical Scalability with Kubernetes Storage Magic» (запись есть на YouTube-канале CNCF).

Кластер PostgreSQL — это primary + произвольное число read-only реплик. Главная ошибка — поспешно навешивать на Postgres ярлык «не масштабируется». Масштабирование не обязательно про разные ноды; на одной ноде тоже можно вытащить максимум из CPU, RAM и storage.

Начинайте с простого

Прежде чем уходить в горизонтальное масштабирование — измерьте. Активный/активный кластер по разным нодам — это ад с точки зрения DR/HA по сравнению с обычной парой primary + standby.

Алгоритм:

  1. Зафиксируйте бизнес-цели: RPO, RTO, нужный TPS.
  2. Прогоняйте бенчмарки: storage — fio, БД — pgbench (либо встроенный OLTP, либо ваши кастомные запросы).
  3. Если результаты не дотягивают — вот тогда смотрите в сторону active/active.

Тонкая настройка вертикали полезна и в распределённой схеме — узлы всё равно нужно выжимать.

Масштабирование томами в CloudNativePG

CloudNativePG управляет PersistentVolumeClaim напрямую, не используя StatefulSet (как делает большинство операторов). Тот же путь выбрала Strimzi для Kafka. Подробности — в разделе «Pod Controller» документации CloudNativePG.

Каждый инстанс обязательно имеет volume для PGDATA — секция storage. Дополнительно (опционально):

Каждому volume можно прописать свой storage class. Это удобно для:

Volume можно добавлять и ресайзить на живом кластере (если CSI поддерживает). Плюсы такого масштабирования:

Интеграция с HA/DR не страдает — поддерживается volume snapshot backup/restore даже для больших БД. Знание сильных/слабых сторон ваших CSI-решений критично.

Отдельный volume для WAL

Минимальный пример:

YAML
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: separate-wal
spec:
  instances: 3
  storage:
    size: 40Gi
  walStorage:
    size: 10Gi
Нажмите, чтобы развернуть и увидеть больше

Каждый инстанс получит два volume — для PGDATA и для WAL. CloudNativePG сам поддерживает symlink, чтобы pg_wal указывал в WAL-volume. Если добавляете WAL-volume на живом кластере — будет rolling update: реплики останавливаются по очереди, WAL переносится, symlink обновляется. Поведение primary настраивается через primaryUpdateMethod (рестарт или switchover).

По бенчмаркам автора, отдельный том под WAL даёт прирост 15–45% в зависимости от соотношения объёмов в памяти и на диске.

Важно правильно засайзить WAL-volume и согласовать с min_wal_size / max_wal_size. Если место кончится — Postgres встанет колом (в CloudNativePG идёт обсуждение, как это смягчить).

Можно прописать отдельный storage class:

YAML
walStorage:
  storageClass: my-favourite-storage-class-for-wals
  size: 10Gi
Нажмите, чтобы развернуть и увидеть больше

Temporary tablespaces

В PostgreSQL можно завести один или несколько временных tablespaces — для temp-таблиц, индексов и временных файлов сортировки. Управляются параметром temp_tablespaces. CloudNativePG абстрагирует это через .spec.tablespaces[*].temporary:

YAML
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: tmp-tablespace
spec:
  instances: 3
  storage:
    size: 40Gi
  walStorage:
    size: 10Gi
  tablespaces:
  - name: tmptbs1
    temporary: true
    storage:
      size: 40Gi
Нажмите, чтобы развернуть и увидеть больше

Проверка:

BASH
kubectl exec -ti tmp-tablespace-1 -c postgres \
  -- psql -c 'SHOW temp_tablespaces'
Нажмите, чтобы развернуть и увидеть больше
PLAINTEXT
 temp_tablespaces
------------------
 tmptbs1
(1 row)
Нажмите, чтобы развернуть и увидеть больше

Можно добавить второй:

YAML
tablespaces:
- name: tmptbs2
  temporary: true
  storage:
    size: 40Gi
Нажмите, чтобы развернуть и увидеть больше

Проверка покажет:

PLAINTEXT
 temp_tablespaces
------------------
 tmptbs1,tmptbs2
(1 row)
Нажмите, чтобы развернуть и увидеть больше

Внутри транзакции PostgreSQL выбирает один tablespace из списка случайно и потом идёт по нему последовательно.

Разделение I/O для индексов и таблиц

Классика: один tablespace под таблицы (data), второй — под индексы (idx):

YAML
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: idx-tablespace
spec:
  instances: 3
  storage:
    size: 40Gi
  walStorage:
    size: 10Gi
  tablespaces:
  - name: data
    storage:
      size: 40Gi
  - name: idx
    storage:
      size: 40Gi
Нажмите, чтобы развернуть и увидеть больше

При создании DDL:

Что дальше

Стек CNPG (Kubernetes + PostgreSQL + CloudNativePG) даёт огромную гибкость по storage. Главное — не утонуть в выборе. Начинайте просто, измеряйте, потом усложняйте. На on-prem активно работайте со storage-вендором — у автора есть бенчмаркинговый набор , который вендоры могут гонять у себя.

И главное — не теряйте данные. Производительность не должна стоить вам durability. Эксперименты «а что если резко выдернуть питание у storage» делайте на planning/test-окружениях, не на проде.

Продолжение — в Рецепте 7.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша