10 способов сделать резервную копию в PostgreSQL

    Многие разговоры про бэкапы начинаются с присказки что люди делятся на две категории… так вот я отношусь к тем людям которые делают бэкапы. Правильно настроенное резервное копирование и проверка резервных копий укрепляет сон. А наличие заранее написаных и проигранных инструкций по восстановлению вообще укрепляет пищеварение и иммунитет. Так вот, за время работы с PostgreSQL мне довелось часто настраивать резервное копирование, при этом условия и требования были самые разные. Однако при этом набор инструментов за редким исключением оставался неизменным. В этой статье поделюсь своим опытом в деле, как можно брать резервные копии PostgreSQL.
    image


    Если рассматривать резервное копирование как вполне конкретный процесс, то возникает два простых вопроса:
    1. откуда запускать резервное копирование?
    2. какие инструменты следует использовать для резервного копирования?

    На первый вопрос есть два варианта ответа: можно запускать задачу резервного копирования с выделенного backup сервера, на мой взгляд это наиболее подходящий вариант. Либо запускать задачу непосредственно с сервера БД, это в случае если нет выделенного сервера бэкапов.

    С инструментами все гораздо интереснее. Здесь я выделяю две группы, основные инструменты и вспомогательные. Основные это те, которые собственно и выполняют резервное копирование. Вспомогательные это те которые добавляют что-то особенное к процессу резервного копирования, например архивирование, шифрование, управление нагрузкой и т.д.

    В комплекте PostgreSQL есть 2 утилиты которые позволяют делать резервные копии, это pg_dump/pg_dumpall и pg_basebackup. Кроме того есть возможность использовать утилиты файлового копирования, такие как rsync, tar, cp и т.п.
    Итак, каким инструментом запускать бэкап?
    pg_dump — подходит для случаев когда нужно сделать резервную копию таблицы, базы, схемы или данных.
    pg_basebackup — подходит для случаев когда нужно сделать резервную копию целиком всего кластера БД или настроить hot standby реплику.
    rsync/tar/cp — также используются для случаев копирования всего кластера.

    Когда только случился релиз PostgreSQL 9.0 резервное копирование выполнялось с помощью rsync, однако уже в 9.1 появился pg_basebackup, который имеет некоторыми преимуществами перед rsync:
    • pg_basebackup не требует ssh доступа, но требует доступа к базе указанного в pg_hba.conf;
    • pg_basebackup богаче по функциональности (копирование WAL, создание recovery.conf, встроенное сжатие gzip и пр.);
    • pg_basebackup не требует отдельного вызова функций pg_start_backup/pg_stop_backup как это требуется при использовании rsync/tar/cp;
    • pg_basebackup выполняет копирование быстрее чем rsync за счет использования протокола потоковой репликации.

    но есть и некоторые недостатки:
    • pg_basebackup идет out-of-the-box, и соответственно требует установленного postgres;
    • pg_basebackup не имеет встроенных функций для ограничения скорости копирования (обещают только в 9.4);
    • pg_basebackup требует включенных опций wal_level = hot_standby, max_wal_senders в postgresql.conf.


    Здесь я буду рассматривать pg_basebackup, хотя и pg_dump тоже может использоваться в нижеперечисленных способах.

    1. Простое и без изысков резервное копирование с backup сервера в каталог /backup (каталог должен быть предварительно создан):
    backup@backup ~ $ pg_basebackup -x -h db01.example.com -U backup -D /backup
    

    2. Копирование с пониженным приоритетом IO операций с помощью ionice, для случаев когда нужно уменьшить нагрузку на дисковый ввод-вывод от резервного копирования:
    postgres@db01 ~ $ ionice -c 3 pg_basebackup -x -h db01.example.com -U backup -D /backup
    

    3. Копирование с сжатием в bzip2, для случаев когда нужно использовать нестандартный для pg_basebackup алгоритм сжатия (gzip). Здесь мы передаем данные через стандартный вывод (stdout) на стандартный ввод (stdin) программе bzip2.
    backup@backup ~ $ pg_basebackup -x --format=tar -h db01.example.com -U backup -D - |bzip2 -9 > /backup/db01/backup-$(date +%Y-%m-%d).tar.bz2
    

    4. Копирование с сжатием в несколько потоков (используем lbzip2 и задействуем 6 ядер). При таком раскладе можно задействовать простаивающие ядра и ускорить процесс сжатия.
    backup@backup ~ $ pg_basebackup -x --format=tar -h db01.example.com -U backup -D - |lbzip2 -n 6 -9 > /backup/db01/backup-$(date +%Y-%m-%d).tar.bz2
    

    5. Здесь копирование запускается на сервере БД. Формируемая резервная копия отправляется на удаленный сервер по ssh.
    postgres@db01 ~ $ pg_basebackup -x --format=tar -h 127.0.0.1 -U backup -D - |ssh backup@backup.example.com "tar xf - -C /backup/"
    

    6. Здесь копирование также запускается на сервере БД и выполняется отправка на удаленный сервер, но уже с архивированием в 6 потоков с помощью lbzip2.
    backup@backup ~ $ pg_basebackup -x --format=tar -h 127.0.0.1 -U backup -D - |ssh backup@backup.example.com "lbzip2 -n 6 -9 > /backup/db01/backup-$(date +%Y-%m-%d).tar.bz2"
    

    7. Копирование на удаленный сервер с ограничением пропускной полосы до 10Мб с помощью pv и последующее архивирование на удаленной стороне. Этот вариант для случаев когда нужно передать не нагружая сеть.
    backup@backup ~ $ pg_basebackup -x --format=tar -h 127.0.0.1 -U backup -D - |pv -r -b -L 10M |ssh backup@backup.example.com "bzip2 -9 > /backup/db01/backup-$(date +%Y-%m-%d).tar.bz2"
    

    Тут стоит отметить что c 9.4 в pg_basebackup уже есть возможность ограничения скорости передачи (-r, --max-rate).
    8. Копирование запускается на backup сервере, а далее происходит раздваивание потока на две части. Один поток сжимается с bzip2 (сам бэкап) и второй поток через tar копируется во временный каталог для последующей валидации. Способ редкоиспользуемый, но тут интересна сама реализация.
    backup@backup ~ $ pg_basebackup -x --format=tar -h db01.example.com -U backup -D - |tee >(bzip2 -9 -c > /backup/db01/backup-$(date +%d-%b-%Y).tar.bz2) |tar xf - -C /backup/validation/
    

    9. Копирование с задействование lbzip2 на обоих узлах, для случаев когда у сети маленькая пропускная способность, сначала поток сжимается, затем передается по сети и затем расжимается на удаленной стороне. Здесь используется tar и требуется выполнение pg_start_backup('label_name') на стороне postgres.
    postgres@master # cd /var/lib/pgsql/9.3/data
    postgres@master # tar cfO - ./ |lbzip2 -n 2 -5 |ssh postgres@standby "lbunzip2 -c -n 2 |tar xf - -C /var/lib/pgsql/9.3/data"
    

    10. бэкапирование с шифрованием через GPG, для случаев когда нужно зашифровать резервную копию. Предварительно следует создать ключи через gpg --gen-key (в моем случае ключи созданы с именем backup)
    backup@backup ~ $ pg_basebackup -x --format=tar -h db01.example.com -U backup -D - |gpg -r backup -e |bzip2 -9 > /backup/db01/backup-$(date +%d-%b-%Y).tar.bz2
    

    Для расшифровки резервной копии следует выполнить такую команду
    backup@backup ~ $ bzcat /backup/backup-09-May-2014.tar.bz2 |gpg -r backup -d |tar xf - -C /example/dir/
    

    На этом все, подведем итоги по инструментам:
    • pg_basebackup — утилита для создания резервных копий postgres;
    • lbzip2 — bzip2 сжатие с использованием несокльких ядер — если нужно запаковать быстрее (аналоги: pbzip2, pigz);
    • ionice — регулировка класса и приоритета для планировщика ввода-вывода (также можно использовать nice для регулировки приоритета процессов для CPU планировщика);
    • pv — контролируем объем передаваемых данных через pipe и т.о. используем для ограничения объема передаваемых данных в единицу времени (аналог — throttle);
    • tar — утилита архивирования, нужна для вспомогательных целей когда неиспользуется сжатие bzip2/gzip;
    • tee — чтение с stdin c записью в stdout и другие файлы (является частью coreutils);
    • gpg — решает задачи по шифрованию.

    Всем спасибо за внимание!
    Share post

    Similar posts

    Comments 18

      +1
      Кстати, шифровать можно и с помощью openssl.
        +2
        Главная проблема pg_basebackup — отсутствие бинарной совместимости между версиями, а иногда приходится восстанавливать бекапы лайвовых баз на девелоперских машинах, где версия постгреса может отличаться… Не могли бы посоветовать статьи по оптимизации создания бекапа по средствам pg_dump? Надеюсь, что увеличение гранулярности базы — не единственный способ уменьшить время бекапа
          0
          Почему не рассмотрены способы бэкапирования бинарных логов? Никакая нагрузка на базу и сеть, восстановление на любой момент времени, малый размер.
            +1
            А разве работа на момент снятия копии не должна быть полностью приостановлена?
              0
              Нет, останавливать ничего не нужно.
                0
                И где тогда гарантия, что вы не заберете базу между двумя зависимыми транзакциями?
                  +1
                  Во время бэкапа (с pg_basebackup) открывается доп. соединение (при использовании -X stream) которое тянет WAL в бэкап, либо WAL сегменты могут быть подтянуты в конце резервного копирования (при -X fetch). Так что все выполненные транзакции также попадут в бэкап.
                  При запуске постгреса с этого бэкапа, WAL журналы будут проиграны при старте и база достигнет состояния на момент времени когда закончилось выполнение pg_basebackup.
                    0
                    Справедливо ли это утверждение так же и для pg_dump?
                    Или для этого случая желательно останавливать приложение, что бы не нарушить целостность базы?
                      +1
                      Нет, для pg_dump это правило не работает.
                0
                Нет, останавливать ничего не нужно.
                  0
                  пардон за дубль… тяжело отвечать на коментарии когда хабр ддосят.
                0
                >> Почему не рассмотрены способы бэкапирования бинарных логов?
                Не совсем понимаю что именно там можно рассматривать. Хм, вобще не думал что с этим могут быть какие-то вопросы/проблемы, там на мой взгляд все довольно просто.
                И там кстати, можно использовать те же подходы что описаны выше.

                >> восстановление на любой момент времени,
                Восстановление надо рассматривать отдельным топиком))) т.к. там много нюансов можно рассмотреть
                0
                А как же такой способ?

                1) SELECT pg_start_backup('label');
                2) делаем снапшот файловой системы
                3) SELECT pg_stop_backup();
                4) спокойно копируем снапшот куда подальше.
                  0
                  pg_basebackup не требует отдельного вызова функций pg_start_backup/pg_stop_backup как это требуется при использовании rsync/tar/cp;
                    0
                    Да можно делать через копирование снимков в т.ч. и с LVM, но я стараюсь не заморачиваться с pg_start/stop_backup, для себя уже выбрал pg_basebackup))
                    0
                    Всё это круто конечно, но вот как проверять целостность БД? — По мне так не один из этих инструментов нормально не может. Например pg_dump, если делает бэкап и допустим где-то БД не целостная, ну например где-то ключ посеяли, он доходит до этого места и просто создает не целостный архив, а точнее кривой. К сожалению инструменты проверки целостности БД в PostgreSQL увы отсутствуют и надо их писать самому…
                      0
                      На ум пришло одно решение: Настраиваем слейв, отключаем его от источника, снимаем с него дамп, подключаем к источнику.
                      Всю последовательность можно в скрипте прописать, думаю, что будет не очень сложно :)
                      0
                      Я раньше пользовался pg_basebackup и pg_dump для создания резервных копий, но этот способ не очень удобен когда мне нужно делать резервную копию каждые 4 часа и отправлять бэкапы на Google Drive. Я нашел эту программу, которая может это делать, может кому-то пригодиться — http://postgresql-backup.com/

                      Only users with full accounts can post comments. Log in, please.