Как стать автором
Обновить

Мгновенные снепшоты postgres на tablespace и btrfs

Время на прочтение4 мин
Количество просмотров8.3K

Yet Another Postrges on BTRFS

Для работы бывает полезно иметь несколько копий одной реальной базы для экспериментов, фикстур или просто тестовых приложений. База растет и время копирования через разворачивание дампа или с помощью шаблона также возрастает до утомительных величин. Для решения этого кейса уже описаны варианты использования файловой системы с поддержкой CoW - Btrfs. В интернете находил  такие инструкции, они сводятся к тому, что делается снепшот всего сервера. И для работы второго "скопированного" нужно перегенерировать pid и сменить порт для предотвращения конфликтов. Этот способ довольно универсальный относительно конфигурации баз на сервере, но кажется имеет ограничение для неопределенного кол-ва параллельных снепшотов серверов.

В этой статье предлагаю свой вариант реализации снепшотов на одном экземпляре сервера postgres и одной базы, на произвольное кол-во копий.

Инструкция linux only, про поддержку CoW файловых систем на Windows не в курсе.

I. Подготовка

1. Нам понадобится специальный раздел для Btrfs, где будут хранится базы и снепштоы.

  • Это может быть отдельное устройство (подключенное аппаратно либо в менеджере виртуальных устройств)

  • Это может быть чистый раздел на текущем устройстве (настроить разделы via cfdisk)

  • Это даже может быть loop device на основе файла (См. losetup)

# Пусть устройство называется
/dev/sdb

2. Отформатируем устройство в Btrfs.

sudo apt-get update && apt-get install -y btrfs-progs
sudo mkfs.btrfs -L btrfs_disk /dev/sdb

3. Примонтируем устройство в систему.

# Для примера возьмем каталог /mnt/btrfs
sudo mkdir -p /mnt/btrfs && sudo mount /dev/sdb /mnt/btrfs

  - (Optional) Можно сделать отдельный каталог только для tablespace.

sudo mkdir /mnt/btrfs/pg

4. Установить postgres сервер, если не установлен.(Инструкцию можно найти на оф. сайте)

II. Для создания начальной базы $ORIGIN(той которую будем снепшотить):

1. Создать подраздел btrfs

sudo btrfs subvolume create /mnt/btrfs/pg/$ORIGIN

   2. Postgres нужны права на этот каталог

sudo chown postgres:postgres /mnt/btrfs/pg/$ORIGIN

   3. Теперь создадим tablespace в этом каталоге. Tablespace может быть назван также как и директория.

psql -c "CREATE TABLESPACE $ORIGIN LOCATION '/mnt/btrfs/pg/$ORIGIN'"

   4. Создадим пустую БД в tablespace.

psql -c "CREATE DATABASE $ORIGIN TABLESPACE $ORIGIN;"

6. Теперь базу можно заполнить данными - из дампа или вашего приложения.

pgbench -i -s 10 $ORIGIN
# Будет отображено время затраченное на генерацию
# У pgbench есть и другие параметры, scale только влияет на кол-во записей и 
# размер базы. (У меня -s 10 дало базу 92Мб)

III. Чтобы сделать снепшот базы $ORIGIN в базу $SNAPSHOT, понадобится:

    1.  Создать простой каталог в pg_btrfs для “каркаса” базы $SNAPSHOT. (Пока это будет БД-пустышка, для того чтобы узнать какой OID назначит сервер)

sudo mkdir /mnt/btrfs/pg/$SNAPSHOT

   2. Не забудем дать права на этот каталог пользователю postgres.

sudo chown postgres:postgres /mnt/btrfs/pg/$SNAPHOT

   3. Создадим в этом каталоге tablespace. 

psql -c "CREATE TABLESPACE $SNAPSHOT LOCATION '/mnt/btrfs/pg/$SNAPSHOT'"

   4. Создадим пустую БД в этом tablespace. 

psql -c "CREATE DATABASE $SNAPSHOT TABLESPACE $SNAPSHOT;"

   5. HINT! Теперь нужно запомнить OID, который будет названием каталога внутри созданной структуры директорий после создания БД. Важно учесть, что такой подход позволяет снепшотить только одну базу в tablespace.

 /mnt/btrfs/pg/
     - $SNAPSHOT/
       - PG_11_201809051  # версия postgres (может отличаться)
         - 99174299 # - DB OID. Запишем ее в переменную
new_oid=$(sudo ls -1 /mnt/btrfs/pg/$SNAPSHOT/PG_*/ | grep -P [0-9]+)

   6. Таким же образом скопируем OID БД $ORIGIN 

origin_oid=$(sudo ls -1 /mnt/btrfs/pg/$ORIGIN/PG_*/ | grep -P [0-9]+)

   7. Теперь удалим обычный каталог, в котором находится tablespace для снепшота. См. сноску [1]. 

sudo rm -rf /mnt/btrfs/pg/$SNAPSHOT/

   8. И наконец сделаем честный снепшот $ORIGIN через btrfs subvolume 

sudo btrfs subvolume snapshot /mnt/btrfs/pg/$ORIGIN/ /mnt/btrfs/pg/$SNAPSHOT

   9. В каталоге /mnt/btrfs/pg/$SNAPSHOT будет Copy-on-Write копия $ORIGIN subvolume с OID как в оригинальной БД. Поэтому переименуем ее, чтобы она выглядела для сервера как БД $SNAPSHOT из пункта 4.

cd /mnt/btrfs/pg/$SNAPSHOT/PG_*/
sudo mv $origin_oid $new_oid
cd -

   10. Теперь можно подключится к БД $SNAPSHOT и проверить, что там те же данные что и в $ORIGIN.

IV. Когда понадобится удалить БД $SNAPSHOT (тоже верно и для $ORIGIN). 

    0. Полезно перед удалением завершить всю активность с базой.

PGQUERY=$(cat<< EOM
   SELECT pg_terminate_backend(pid)
   FROM pg_stat_activity
   WHERE pid <> pg_backend_pid()
      AND datname = '$SNAPSHOT';
    EOM
    )
psql -c "$PGQUERY"

    1. Удаляем базу $SNAPSHOT

psql -c "DROP DATABASE IF EXISTS $SNAPSHOT;"

    2. Удаляем tablespace $SNAPSHOT

psql -c "DROP TABLESPACE IF EXISTS $SNAPSHOT;

    3. Удаляем subvolume btrfs.

btrfs subvolume delete /mnt/btrfs/pg/$SNAPSHOT

V. Если нужно выполнить восстановление состояния из $ORIGING в $SNAPSHOT:

    1. Повторяем шаги для удаления $SNAPSHOT

    2. Повторяем шаги для создания $SNAPSHOT из $ORIGIN

[1] Шаги II.1-6 нужны только для создания OID базы данных в tablespace. Удаление каталога в котором зарегистрирован tablespace не должен сломать postgres(но не думаю, что будет хорошей мыслью делать запросы во время создания снепшота). Мета информация о базах и tablespace-ах продолжает хранится в системной базе postgres, и мы на нее не влияем. Возможно, есть и другой способ создания OID базы данные и его подмена в снепшот $ORIGIN, если вы знаете такой, пожалуйста поделитесь.


P.S. Этот способ очень помог мне на работе, где нужно было каждый день проверять ошибки пользователей в системе на реальных данных, т.е. копии из продакшн. База занимала больше 100Гб, а разворачивание дампа около часа. По старинке, после разворачивания тестовая база захламлялась патчами или миграциями разных разработчиков и данные в ней начинали конфликтовать. Тогда нужно либо иметь запас развернутых копий БД, либо ждать пока удалится и восстановиться новая.

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

Все эти шаги были вынесены в 3 bash скрипта, которые совпадают с последними тремя разделами, и запускались через jenkins. За год работы проблем на стороне btrfs или postgres замечено не было. 

Теги:
Хабы:
Всего голосов 12: ↑12 и ↓0+12
Комментарии9

Публикации

Ближайшие события