Можно сколько угодно спорить о преимуществах/недостатках открытого и проприетарного ПО, но иногда последнее все-таки имеет некоторые преимущества, выражающееся хотя бы в некотором удобстве в работе для администратора.
Задача :
Создание резервных копии "немаленьких" БД с возможностью PITR (Point in Time Recovery) и минимальным влиянием на СУБД. В целом постановка задачи сразу же намекает на использование физических бэкапов с возможностью создания инкрементальных копий.
Как это делается в "кровавом" enterprise-уровня проприетарном решении от Oracle :
При помощи RMAN (Recovery Manager) и простого сценария создаем простую политику инкрементально-обновляемой копии БД (Image Copy) :
RUN {
RECOVER COPY OF DATABASE WITH TAG 'DB_INC_BACKUP' UNTIL TIME 'SYSDATE - 7';
BACKUP INCREMENTAL LEVEL 1 FOR RECOVER OF COPY WITH TAG 'DB_INC_BACKUP' DATABASE;
}
Данный сценарий выполнит в первый запуск бэкап уровня 0 (ака Full Backup с возможностью стать "основой" для Incremental), далее будут выполняться инкрементальные бэкап уровня 1 (частота выполнения их уже на совести администратора), восстановление которых ("накат" изменений на бэкап уровня 0) будет выполняться в режиме "плавающего" окна восстановления, равного 7 дням. Таким образом 2.5 строчки кода сценария позволяет нам полностью решить поставленную задачу, бэкап при этом "синтетический" и оптимальный по занимаемому месту для хранения.
А теперь посмотрим как реализовать аналогичное, например, для MariaDB, свободной с оговорками СУБД, которая часто (и по некоторым возможностям заслуженно) встречается в бизнес-задачах.
Для поиска аналогичного решения беремся за официальную документацию, документацию сторонних разработчиков решений enterprise-уровня (например Percona) на основе свободных версий указанных БД, обзор поделок на github и тп, но приходим лишь к единственному аналогичному RMAN решению - утилите mariabackup (пакет mariadb-backup), "новое" название для продукта xtrabackup. При этом выясняется , что какой-либо автоматизации для управления резервными копиями здесь нет и весь аналогичный функционал нужно реализовать самостоятельно.
Приведу несколько примеров в виде функций и фрагментов *sh - скрипта, которые можно использовать для написания скрипта реализации РК под свои задачи:
Полный бэкап (первый бэкап, базовый для последующих инкрементальных копий ), в $1 передаем путь "куда положить" полный бэкап:
bkp_full () {
/usr/bin/mariabackup --backup --target-dir=$1 --user=$backup_user
}
Инкрементальный бэкап на основе указанной предыдущей созданной копии (полный или инкрементальный бэкап) , в $1 передаем путь "куда положить" инкрементальный бэкап, в $2 - указываем путь до предыдущей созданной копии (полный или инкрементальный бэкап) :
bkp_inc () {
/usr/bin/mariabackup --backup --target-dir=$1 --incremental-basedir=$2 --user=$backup_user
}
Подготовка полного бэкапа к операции восстановления/наката инкрементальных изменений, по сути это накат redo логов, которые накопились при выполнении задачи полного бэкапа (на больших БД это может быть действительно долго), в $1 передаем путь к полному бэкапу :
prep_full () {
/usr/bin/mariabackup --prepare --target-dir=$1
}
Подготовка полного бэкапа к операции восстановления/наката инкрементальных изменений, в $1 передаем путь к полному бэкапу, в $2 - путь к инкрементальному бэкапу
prep_inc () {
/usr/bin/mariabackup --prepare --target-dir=$1 --incremental-dir=$2
}
Все основные функции готовы, осталось описать процесс, аналогичный указанному выше сценарию Oracle RMAN.
Для простоты изложения приведу основные (упрощенные) этапы выполнения сценария скрипта и вызовы функций :
rec_win=10080 # Окно восстановления в минутах
b_basepath=/db/backup # Базовый путь для хранения бэкапов
full_b_path=$b_basepath/000_fullbackup # Полный бэкап
inc_b_path=$b_basepath # Инкрементальные копии
Проверяем не пустая ли директория
dir_empty () {
/usr/bin/find $1 -empty -type d
}
Ищем самый "старый" бэкап
oldest_inc_b () {
declare -a days=($(/usr/bin/ls $inc_b_path))
echo ${days[1]}
}
Ищем самый "свежий" бэкап
newest_inc_b () {
declare -a days=($(/usr/bin/ls $inc_b_path))
echo ${days[-1]}
}
Делаем первую полную копию, подготавливаем полный бэкап для восстановления
if [[ ! -d "$full_b_path" ]] || [[ "$(dir_empty "$full_b_path")" ]]; then
/usr/bin/mkdir -p "$full_b_path"
bkp_full $full_b_path
prep_full $full_b_path
exit 0
fi
Определяем самый "свежий" бэкап и путь для "сегодняшней" инкрементальной копии
newest_inc_b_path="$inc_b_path"/"$(newest_inc_b)"
current_inc_b_path="$inc_b_path"/"$(date +%Y%m%d%H%M%S)"
/usr/bin/mkdir -p "$current_inc_b_path"
Создаем инкрементальную копию на основе имеющегося самого "свежего" бэкапа
if [[ "$current_inc_b_path" != "$newest_inc_b_path" ]]; then
bkp_inc "$currest_inc_b_path" "$newest_inc_b_path"
fi
Определяем самый "старый" бэкап и соответствующий ему путь.
Накатываем самые "старые" копии до выполнения условия - пока есть резервные копии старше даты, заданной в соответствии с параметром окна восстановления, удаляем те копии, которые уже применили при восстановлении.
oldest_inc_b_path="$inc_b_path"/"$(oldest_inc_b)"
if [[ "$oldest_inc_b_path" != "$full_b_path" ]]; then
while [ "$(oldest_inc_b)" -lt "$(date --date="$rec_win minute ago" +%Y%m%d%H%M%S)" ]; do
oldest_inc_b_path="$inc_b_path"/"$(oldest_inc_b)"
if [[ "$oldest_inc_b_path" != "$full_b_path" ]]; then
prep_inc "$full_b_path" "$oldest_inc_b_path" && rm -rf "$oldest_inc_b_path"
else
exit 0
fi
done;
fi
Таким образом, хоть и гораздо менее комфортно для администатора БД, достигаем аналогичного решения поставленной задачи, как и с помощью приведенного выше сценария Oracle RMAN.