UMGUM.COM 

Прореживание бэкапов ( Оптимизация хранения большого количества резервных копий путём простейшего удаления избыточных. )

30 марта 2017  (обновлено 10 февраля 2018)

OS: Linux Debian/Ubuntu.

Известное правило эксплуатационщика гласит: "резервных копий не бывает много". Следуя ему я обычно сохраняю данные двумя способами: посредством централизованной гибко настраиваемой системы вроде "Acronis/Bacula/Veeam" и локально по расписанию скриптами Bash.

Тема работы со специализированными программными комплексами обширная, но здесь не об этом. Каждый сколь либо активно работающий сервер я прежде всего бэкаплю простейшим архивированием важных файлов, а также выгрузкой полного среза "баз данных" - отчего даже на сервере с простым набором сервисов каждый день появляется минимум два новых файла с резервными копиями. На практике разного рода типа бэкапов бывает больше, количество файлов растёт, и очень скоро в полный рост встаёт вопрос об их ротации или прореживании, если история изменения данных важна.

Мой подход к организации хранения резервных копий базируется на соблюдении следующих правил:

1. Все файлы резервных копий содержат в именах дату создания таковых в формате "YYYY-MM-DD".
2. При определении даты создания файла опираемся на указанное в имени такового, а не на метку времени файловой системы.
3. Периодически (раз в два-три дня) запускаем процедуру прореживание файлов резервных копий.
4. Всегда оставляем нетронутым резервные копии за последнюю неделю.
5. Оставляем по одному набору файлов в месяц (обычно за последний день).

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


Пишем скрипт прореживания резервных копий.

Мне нравится использовать встроенное в несущие операционные системы программное обеспечение. "Bash" есть везде и всегда, так что выбор очевиден. Готовим место для скрипта и пишем таковой:

# mkdir -p /usr/local/etc/backup
# vi /usr/local/etc/backup/backups-thinning.sh
# chmod ugo+x /usr/local/etc/backup/backups-thinning.sh

#!/bin/bash

# Месторасположение директорий с резервными копиями.
DPATH="/var/backups/web"

# Месторасположение журнала событий.
LOG="/var/log/backups-thinning.log"

# # Прореживаем бэкапы за прошедший месяц (за исключением ближайшей недели), оставляя по одному последнему в месяце. # #

# # Опираемся на имена файлов, содержащие даты в формате "YYYY-MM-DD", а не на метку времени создания таковых в файловой системе! # #

# Получаем перечень всех дат формата "YYYY-MM-DD", содержащихся в именах файлов,
# сортируя даты с исключением дубликатов, и выводим список в массив переменных.
ADAYS=( $(/usr/bin/find ${DPATH} -maxdepth 1 -type f | grep -E -o -z "[0-9]{4}-[0-9]{2}-[0-9]{2}" | sort -u -z | xargs --null -I {} echo {}) )

# Проходим (опираясь на "индексы") по массиву дат, нормализуя перечень.
for I in "${!ADAYS[@]}"; do

  # Пропускаем строки, которые не содержат корректных дат формата "YYYY-MM-DD".
  date +%Y-%m-%d -d "${ADAYS[$I]}" > /dev/null 2>&1; [ ${?} -ne 0 ] && { unset ADAYS[$I]; continue; }

  # Пропускаем строки, содержащие даты ближе недели к текущей (они не подлежат удалению).
  [ $(date +%s -d "${ADAYS[$I]}") -gt $(date +%s -d "7 day ago") ] && { unset ADAYS[$I]; continue; }
done
unset I

# Вычленяем из перечня дней список упомянутых сочетаний "год-месяц" в формате "YYYY-MM".
AMONTHS=( $(printf "%s\n" "${ADAYS[@]}" | grep -E -o "[0-9]{4}-[0-9]{2}" | sort -u) )

# Фиксируем время начала процедуры прореживания.
echo >> ${LOG}; echo "Thinning start at $(date +%Y-%m-%dT%H:%M):" >> ${LOG}

# Перебираем все месяцы, содержащиеся в именах файлов бэкапов.
for I in "${!AMONTHS[@]}"; do

  # Выбираем все упоминаемые дни обрабатываемого месяца, вычёркивая последний из списка дней обрабатываемого месяца.
  ATRGS=( $(printf "%s\n" "${ADAYS[@]}" | grep "${AMONTHS[$I]}" | sort -u | head -n -1) )

  # Проходим по перечню отфильтрованных дат и удаляем файлы, подпадающие под маску.
  for II in "${!ATRGS[@]}"; do

    ls ${DPATH}/*${ATRGS[$II]}* >> ${LOG}
    rm --force ${DPATH}/*${ATRGS[$II]}*
  done
  unset II

  # Зачищаем массив исполнительных данных для следующей итерации.
  unset ATRGS
done
unset I

exit 0

Регистрируем расписание.

Естественно, что процедура прореживания цикличных бэкапов по определению периодична, так что настроим запуск по расписанию (например раз сутки, после полуночи):

# vi /etc/crontab

....
# Backups daily thinning
0 3  * * *  root  /usr/local/etc/backup/backups-thinning.sh &


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )