Pull to refresh

Как не потерять данные в PostgreSQL

Reading time 5 min
Views 61K
PostgreSQL предлагает несколько вариантов резервирования данных. Обо всех них уже рассказано не раз, в том числе и на хабре. Но в основном рассказывается про технические особенности методов. Я же хочу постараться рассказать про общую стратегию резервного копирования, объединив все методы в эффективную систему, которая поможет вам сохранить все данные и уменьшить число погибших нервных клеток в критических ситуациях.
Вводные данные: сервер PostgreSQL 9.2, База размером >100Gb.

Варианты бекапа

Как следует из мануалов, есть 3 метода резервирования данных:
  • Потоковая репликация
  • Копирование файлов БД
  • SQL-дампы

Все они имеют свои особенности, поэтому мы используем все эти методы.

Потоковая репликация

Настройка потоковой репликации хорошо описана в статьях здесь и здесь. Смысл этой репликации в том, что если основной сервер упадет, то слейв можно быстро сделать мастером и работать с ним, т.к. на слейве находится полная копия БД.
В потоковой репликации большое значение имеют WAL-файлы. Это файлы, откуда слейв подтягивает недостающие данные, если на мастере их уже не осталось. Отсюда есть необходимость хранить эти WAL-файлы подольше. Мы храним эти файлы 8 дней.
Директория с WAL-файлами должна быть доступна как мастеру (на запись), так и слейву (на чтение). Чтобы обеспечить это, мы создали общее хранилище на базе glusterFS, которое подмонтировали на обоих серверах. Таким образом, во-первых, достигается бОльшая надежность (при падении мастера wal-файлы будут доступны для слейва), а во-вторых есть возможность быстрого создания дополнительных слейвов, которым тоже понадобятся эти wal.
Итог: потоковая репликация защитит от сбоев основного сервера, при этом почти никакие данные не потеряются.

Копирование файлов БД

С падением сервера разобрались, теперь разберемся с человеческим фактором, когда по какой-то причине удалены данные в таблицах, либо сами таблицы или базы банных. В этом случае придется восстанавливать данные из резервной копии. Еще копия БД может потребоваться для тестирования приложения. Такую копию можно сделать двумя способами — сделать дамп базы либо скопировать всю директорию с данными. Долгое время мы использовали первый вариант — дампили БД в файл. Но у дампа есть большой минус — процесс блокирует таблицы, и другие процессы уже не могут с ними работать (UPD: pg_dump не блокирует таблицы. Однако, он создает большую нагрузку на БД). Для больших БД это критично.
Сейчас для резервного копирования БД мы используем утилиту pg_basebackup, которая по сути копирует все файлы БД в один большой архив.
Мы сохраняем 4 недельных копии и 6 месячных. Копии храним на том же хранилище GlusterFS. Копии мы создаем таким образом, чтобы они были самодостаточны, то есть работали сразу после развертывания, без необходимости подгрузки дополнительных WAL-файлов. Поэтому мы можем без проблем развернуть базу, к примеру, трехмесячной давности.
Примечательно то, что утилиту pg_basebackup можно запускать (при определенных условиях) на слейв-сервере, поэтому создание резервных копий абсолютно никак не нагружает мастер.
Чтобы pg_basebackup работал на слейве, нужно включить сохранение WAL-файлов, для этого установить опции в postgresql.conf:
wal_level = hot_standby
wal_keep_segments = 1000 

1000 — это количество wal-файлов, которые postgreSQL хранит на диске. Вам, возможно, нужно будет уменьшить или увеличить этот параметр. Дело в том, что pg_basebackup просто архивирует содержимое БД, однако во время архивации некоторые данные уже изменятся, и эти изменившиеся данные PostgreSQL потом при восстановлении подтянет из WAL-файлов. Для этого pg_basebackup сохранит в архив также все существующие WAL-файлы. Таким образом, чтобы все прошло успешно, нужно, чтобы были в наличии все WAL-файлы с момента начала работы pg_basebackup до момента его завершения. Если нужные WAL-файлы удалятся, то pg_basebackup завершится с ошибкой. Нужное количество wal_keep_segments можно определить опытным путем.
Чтобы создать резервную копию БД, мы запускаем pg_basebackup с такими параметрами:
/usr/bin/pg_basebackup -U postgres -D /tmp/pg_backup -Ft -z -Xf

-F говорит нам, что нужно сохранить все в один файл, -z — что нужно заархивировать, -Xf — включить в архив WAL-файлы. Без включения WAL-файлов бекап отработает, но при восстановлении Postgres потребует предоставить недостающие WAL-файлы.

Бекап мы делаем по крону по субботам вот таким скриптом:
#!/bin/bash

mkdir /tmp/pg_backup
/usr/bin/pg_basebackup -U postgres -D /tmp/pg_backup -Ft -z -Xf

WEEK=$(date +"%V")
MONTH=$(date +"%b")
let "INDEX = WEEK % 5"

test -e /collector/db-backup/base.${INDEX}.tar.gz && rm /collector/db-backup/base.${INDEX}.tar.gz
cp /tmp/pg_backup/base.tar.gz /collector/db-backup/base.${INDEX}.tar.gz

test -e /collector/db-backup/base.${MONTH}.tar.gz && rm /collector/db-backup/base.${MONTH}.tar.gz
ln /collector/db-backup/base.${INDEX}.tar.gz /collector/db-backup/base.${MONTH}.tar.gz

test -e /collector/db-backup/base.last.tar.gz && rm /collector/db-backup/base.last.tar.gz
ln /collector/db-backup/base.${INDEX}.tar.gz /collector/db-backup/base.last.tar.gz

rm -r /tmp/pg_backup

Таким образом создается файл с 3 суффиксами: с номером недели, с названием месяца и служебным last.
Чтобы восстановить БД из копии, нужно остановить PostgreSQL, удалить (или перенести) старые данные из data-директории, распаковать туда содержимое архива и запустить сервер. Тут есть один интересный момент. Так как pg_basebackup мы делали на слейве, то вместе с данными распакуется и файл recovery.conf. Так вот, если мы хотим восстановить данные на последнее возможное состояние, то этот файл нужно оставить, в этом случае после запуска сервера Postgres начнет подтягивать WAL-файлы из места, указанного в recovery.conf. Если взять последний недельный бекап, то у нас будут все нужные WAL-файлы (т.к. мы храним их 8 дней), и мы сможем восстановить БД до последнего нормального состояния.
Если же нам нужны данные по состоянию на время создания резервной копии, то перед запуском БД нужно удалить файл recovery.conf.

Резервные копии мы также используем для тестовых целей, за одним проверяется и корректность создания резервной копии.
Имя base.last.tar.gz используется нами для восстановления последней копии в тестовую БД. Тестовая БД у нас восстанавливается каждую ночь вот таким скриптом:
#!/bin/bash
/etc/init.d/postgresql stop
rm -r /data/*
tar -zxf /collector/db-backup/base.last.tar.gz -C /data/
rm /data/recovery.conf
/etc/init.d/postgresql start


Итог: копирование БД на файловом уровне защитит от программных сбоев и человеческих ошибок. При восстановлении БД из резервной копии потеряются последние данные.

SQL-дампы

Мы давно не делаем полный SQL-дамп большой БД, зато делаем дампы изменившихся таблиц, 1 таблица — 1 файл. Это позволяет очень быстро восстановить данные в случаях, когда испорчена только одна таблица — не нужно распаковывать всю БД из резервной копии.
PostgreSQL предоставляет нам статистику по количеству изменений в таблицах, и каждую ночь мы смотрим, какие таблицы были изменены, и их дампим. Статистику смотрим примерно таким вот запросом:
select schemaname,relname,n_tup_ins+n_tup_upd+n_tup_del from pg_stat_user_tables ;
Итог: SQL-дамп поможет восстановить незначительные ошибки. При этом данные будут актуальны на момент создания дампа.

In conclusion

Как видим, чтобы максимально защитить себя от потери данных, можно и нужно использовать все возможности PostgreSQL, тем более, что это не так и сложно.
Tags:
Hubs:
+28
Comments 16
Comments Comments 16

Articles