Урок по треку DevOps: CI/CD, IaC, облака 8 мин

Базы данных в эксплуатации за 8 минут

Бэкапы и PITR, проверка восстановления, репликация, failover, пулы соединений, миграции без простоя.

DevOps не пишет запросы за разработчиков, но отвечает за то, чтобы база не потеряла данные, пережила отказ сервера и обновлялась без простоя. Примеры на PostgreSQL: его чаще всего спрашивают в РФ.

RPO и RTO

  • RPO (Recovery Point Objective): сколько данных можно потерять. «Не больше 5 минут» значит, что бэкап раз в сутки не подходит.
  • RTO (Recovery Time Objective): за сколько надо восстановиться. «Час» значит, что восстановление 2 ТБ из логического дампа за 10 часов не подходит.

Сначала договариваются о RPO и RTO с бизнесом, потом выбирают способ бэкапа.

Логические и физические бэкапы

  • Логический (pg_dump): SQL или собственный формат с данными одной базы. Согласован на момент начала дампа, переносим между версиями, можно восстановить одну таблицу. Минусы: долго на больших базах, восстановление ещё дольше (пересоздание индексов), точка восстановления только момент дампа.
  • Физический (pg_basebackup, pgBackRest, WAL-G, Barman): копия файлов кластера плюс журнал WAL. Быстрое восстановление больших баз и PITR (point-in-time recovery): восстановиться на любой момент, например на 14:31:59, за секунду до того, как кто-то выполнил DELETE без WHERE.
pg_dump -Fc -d app -f app.dump          # формат custom, сжатый
pg_restore -d app_restored -j 4 app.dump  # восстановление в 4 потока

PITR работает так: базовая копия плюс непрерывно архивируемые сегменты WAL. При восстановлении берут базовую копию и проигрывают WAL до нужного момента (recovery_target_time).

Правила бэкапов

  • 3-2-1: три копии, на двух разных типах носителей, одна вне площадки. Бэкап на том же диске или в том же аккаунте облака не спасёт от удаления аккаунта или шифровальщика.
  • Неизменяемость: объектное хранилище с блокировкой объектов или отдельный аккаунт без права удаления.
  • Проверка восстановления: бэкап, из которого ни разу не восстанавливались, это гипотеза. Регулярно восстанавливайте на отдельный стенд автоматически и проверяйте данные.
  • Мониторинг: алерт, если бэкап не создался или стал подозрительно маленьким.

Репликация

  • Потоковая (физическая): реплика получает WAL с мастера и применяет его. Реплики можно использовать для чтения и как кандидатов на failover.
  • Асинхронная (по умолчанию): мастер не ждёт реплику, при падении мастера последние транзакции могут потеряться.
  • Синхронная: коммит ждёт подтверждения реплики (synchronous_standby_names). Надёжнее, но медленнее, и если синхронная реплика недоступна, запись встанет, если не настроить запасную.
  • Логическая (publication / subscription): передаёт изменения строк, работает между разными мажорными версиями. Используют для обновлений почти без простоя и для выборочной репликации.

Лаг репликации нужно мониторить: чтение с отстающей реплики возвращает старые данные («создал заказ, а в списке его нет»).

Failover

Автоматическое переключение на реплику делают Patroni (с etcd или Consul для выбора лидера), в managed-базах облако. Главная опасность split-brain: два узла считают себя мастером и принимают запись. Защищаются консенсусом (лидер только с большинством голосов) и fencing: старый мастер отключают от записи. Приложение должно переподключаться: через виртуальный IP, DNS, HAProxy или PgBouncer, который знает текущего лидера.

Пулы соединений

Каждое соединение PostgreSQL это отдельный процесс с памятью. Тысяча подов по 20 соединений исчерпают max_connections и память. PgBouncer держит небольшое число серверных соединений и раздаёт их клиентам:

  • session: соединение закреплено за клиентом на всю сессию;
  • transaction: только на время транзакции, самый эффективный режим. Не работают сессионные вещи: SET без LOCAL, advisory-блокировки уровня сессии, LISTEN;
  • statement: на один запрос, транзакции из нескольких запросов невозможны.

Миграции без простоя

Проблема не в длительности миграции, а в блокировках. Многие ALTER TABLE берут блокировку ACCESS EXCLUSIVE, и пока она ждёт долгий запрос, за ней в очереди встают все остальные запросы к таблице. Правила:

  • SET lock_timeout = '3s' в миграции: лучше упасть и повторить, чем повесить всю таблицу.
  • CREATE INDEX CONCURRENTLY вместо обычного (не внутри транзакции; при ошибке остаётся невалидный индекс, его удаляют и создают снова).
  • Добавление колонки с константным DEFAULT быстрое с PostgreSQL 11, а смена типа колонки часто переписывает всю таблицу.
  • Внешний ключ и CHECK: сначала ADD CONSTRAINT ... NOT VALID (быстро), потом VALIDATE CONSTRAINT (проверка без блокировки записи).
  • Массовые UPDATE пачками по несколько тысяч строк, а не одним запросом на 50 миллионов.
  • Переименование и удаление колонок только через expand/contract.

Мажорное обновление

Варианты: pg_upgrade (быстро с --link, но с простоем на время работы), логическая репликация в новый кластер с переключением (минуты простоя), дамп и восстановление (долго, для небольших баз). Всегда с репетицией на копии.

Частые ошибки

  • Бэкапы есть, восстановление ни разу не проверяли.
  • Бэкапы в том же облачном аккаунте, что и база.
  • Каждый под открывает 50 соединений напрямую к базе.
  • CREATE INDEX без CONCURRENTLY на горячей таблице в рабочее время.
  • Чтение с асинхронной реплики сразу после записи.

Что спросят на собесе

  • Чем логический бэкап отличается от физического и что такое PITR.
  • Что такое RPO и RTO и как от них зависит стратегия.
  • Синхронная и асинхронная репликация, что такое split-brain.
  • Зачем PgBouncer и какие у него режимы.
  • Как добавить индекс или внешний ключ на большую таблицу без простоя.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.