У штуки под названием postgres есть очень хороший способ бекапа. Называется он PITR. Стандартный процесс бэкапа выглядит так:
touch /var/lib/pgsql/backup_in_progress psql -c "select pg_start_backup('hot_backup');" tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/ psql -c "select pg_stop_backup();" rm /var/lib/pgsql/backup_in_progress tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
В чем засада? Засада в tar. В данном случае он тупо копирует весь каталог postgres со всеми потрохами. А это дает дикую нагрузку на диск, что в реальной жизни огорчает postgres до изумления. Конечно если есть возможность, то лучше создавать такой tar где-нибудь на другом диске или даже сервере, а если нет? И нет возможности поднять где-нибудь slave сервер и делать бекапы с него?
Первым предположением будет добавить ключик z или j – пусть сразу пакует. И тут сразу же возникает проблема: нельзя добавить файликов в уже запакованный tar. Надо распаковывать, добавлять и снова запаковывать. Какие есть пути решения?
1. Так и таскать два .tar.gz файла. Одиним меньше, другим больше …
2. Забить и переложить проблему на админов сторов. Пусть дают больше места и скорости.
3. Сделать скрипт, который где-то там, далеко, будет перепаковывать файлы. Заодно и целостность бекапа проверит.
Но я решил пойти другим путем. Он чуть-чуть посложнее, но зато результатом становится один сжатый файл. Вот упрощенный псевдокод:
mkfifo backup_fifo sleep 98765 > backup_fifo stdbuf -i0 -o0 -e0 cat backup_fifo | cpio -o -H tar | pigz -q > /path/to/backup.gz psql -c "select pg_start_backup('hot_backup');" stdbuf -i0 -o0 -e0 find postgres/data -type f > backup_fifo psql -c "select pg_stop_backup();" stdbuf -i0 -o0 -e0 find postgres/archive -type f > backup_fifo kill sleep
Расскажу последовательно:
mkfifo backup_fifo
. Создаем fifo фаил. Он будет у нас очередью для имен файлов, подлежащих архивированию.
sleep 98765 > backup_fifo
. Открываем fifo и держим его открытым. Думаю, что 68 суток должно хватить для любого бекапа.
cat backup_fifo | cpio -o -H tar | pigz -q
Запускаем процесс “таренья” всего, чьи имена прилетят в fifo. Так как tar не умеет читать имена файлов с stdin, использовал cpio в режиме tar. Ну и pigz – это параллельный gzip.
А дальше полностью повторяем стандартный процесс бекапа postgres, без каких-либо отступлений от генеральной линии. В конце прибиваем sleep и fifo закрывается, закрывая за собой все остальное.
В чем тонкости?
1. Использование sleep в качестве держалки для fifo. Я больше не смог вспомнить ни одной утилиты, которые ничего никуда не пишут, но открывают stdout & stdin.
2. Использование stdbuf. Если её не использовать, то из-за буферизации будет невозможно понять, какой и когда закончился этап. В результате легко получается, что tar забирает не то, что нужно.
Для предотвращения гонок в пункте 2 я пробовал вставлять в бекап файлы-маркеры и потом отслеживать время доступа к ним, но решение получилось … не элегантным и потребовало третий поток для исполнения.
Понятно, что в реальном скрипте все обвешано проверками и прочими тонкостями, но суть я скопипастил точно.
ЗЫ Картинку честно стащил из интернета.