Статьи

Создание надежной системы резервного копирования

В Foreach у нас есть Synology RS815 + для хранения всех наших резервных копий. Эти резервные копии поступают из разных источников в нашей сети, таких как маршрутизаторы, коммутаторы, серверы баз данных, веб-серверы, файлы журналов приложений, почтовые серверы и т. Д.

NAS-устройство Synology упрощает настройку общих файловых ресурсов и квот для этих резервных копий. Тем не менее, ему не хватало нескольких функций:

  • Мониторинг квот на общих файловых ресурсах (жесткие квоты, а также на файловые ресурсы без квот).
  • Удаление устаревших файлов резервных копий, предопределенных политикой хранения.
  • Проверка файлов резервных копий, чтобы убедиться, что мы действительно получили файлы резервных копий.

В этом сообщении мы расскажем, как настроить приложение Spring Boot 2, которое предоставляет графический интерфейс и может отслеживаться, например, с помощью Zabbix.

О резервное копирование, где ты?

Вы можете распознать следующую проблему:

Вам необходимо восстановить резервную копию и перейти в свою папку только для того, чтобы убедиться, что файла резервной копии там нет. Вы начинаете копаться и обнаруживаете, что резервная копия никогда не поступала на ваш NAS, потому что квота вашей общей папки была превышена. Или, что еще хуже, весь ваш NAS был фактически заполнен. Черт! Мы должны были очистить наши резервные файлы 3 года назад!

Если боги несколько хороши для вас, вы действительно найдете файл резервной копии, но он может быть устаревшим или слишком старым для восстановления. Требуемые вами данные должны быть получены не более 3 дней назад, а несколько дней назад. Слей это! Мы должны были проверить, действительно ли задачи резервного копирования работали!

Эврика!

Чтобы решить эту проблему, мы создали приложение Spring Boot 2.0, которое выполняет несколько функций:

  • Он предоставляет графический интерфейс, основанный на Bootstrap, который доступен для чтения (да!), И платформу мониторинга (в нашем случае Zabbix).
  • Он отслеживает все общие файловые ресурсы, которые настроены в нашей Synology, и предупреждает нас, если лимиты квот близки к достижению.
  • Он удаляет старые файлы резервных копий из общих папок на основе политики хранения.
  • Он проверяет файлы резервных копий и гарантирует, что файлы достаточно свежие и что имеется определенное количество доступной истории.

Конечный результат выглядит так:

Настройка высокого уровня

Мы использовали Spring Initialzr для создания проекта Maven с Java 8 и Spring Boot 2.0. Thymeleaf 3 и Bootstrap 3 были использованы для создания страницы обзора.

Используя jquery / bootstrap webjars, мы смогли настроить контроллер и макет прототипа всего за несколько минут.

Global status: OK — обязательная строка, которая отслеживается Zabbix. В случае сбоя какого-либо из базовых статусов глобальный статус также не будет выполнен.

Мы развернули приложение, используя толстую банку Spring Boot в своей общей файловой папке (вы не хотите, чтобы файлы журнала приложения заполняли другие резервные папки, верно?). Чтобы создать исполняемый файл jar, добавьте следующее в ваш pom.xml . Смотрите документацию для получения дополнительной информации.

01
02
03
04
05
06
07
08
09
10
11
12
<build>
       <finalName>checkback</finalName>
       <plugins>
            <plugin>
              <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                 <executable>true</executable>
                 </configuration>
            </plugin>
       </plugins>
</build>

Synology NAS на самом деле не поставляется со стандартной средой System V. Чтобы воспользоваться преимуществами сценариев запуска / остановки, встроенных в исполняемый файл jar, я прочитал, как на самом деле работает встроенный сценарий запуска. Вы можете найти его на GitHub.

Основной момент здесь:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
# Follow symlinks to find the real jar and detect init.d script
cd "$(dirname "$0")" || exit 1
[ [ -z "$jarfile" ] ] && jarfile=$(pwd)/$(basename "$0")
while [ [ -L "$jarfile" ] ]; do
  if [ [ "$jarfile" =~ init\.d ] ]; then
    init_script=$(basename "$jarfile")
  else
    configfile="${jarfile%.*}.conf"
    # shellcheck source=/dev/null
    [ [ -r ${configfile} ] ] && source "${configfile}"
  fi
    jarfile=$(readlink "$jarfile")
    cd "$(dirname "$jarfile")" || exit 1
    jarfile=$(pwd)/$(basename "$jarfile")
done

По сути, он проверяет, где находится файл .jar. Если файл .jar фактически находится в каталоге с именем «init.d» (расположение не должно быть /etc/init.d), он будет рассматриваться как сценарий запуска / остановки. Вам нужно только создать каталог init.d где-нибудь и создать символическую ссылку от сценария start / stop к исполняемому файлу jar.

В нашей среде мы получили следующую структуру приложения:

/volume1/checkback ( /volume1/checkback папка для этого приложения)

/volume1/checkback/checkback.jar (исполняемый файл- /volume1/checkback/checkback.jar Spring Boot)

/volume1/checkback/checkback.conf (файл конфигурации приложения Spring Boot)

/volume1/checkback/init.d/checkback.sh (символическая ссылка на /volume1/checkback/checkback.jar)

Имея это в виду, мы можем запускать / останавливать и видеть состояние нашего приложения Spring Boot. Также можно создать запуск запуска в Synology NAS, таким образом, ваше приложение будет запускаться всякий раз, когда ваша Synology перезагружается для их исправлений.

1
2
3
user@synology:/volume1/checkback/init.d$ ./checkback.sh status
Running [18657]
user@synology:/volume1/checkback/init.d$

Файл checkback.conf содержит расположение нашего производственного конфигурационного файла, а также указывает папку журнала (вместо расположения по умолчанию / var / log)

1
2
3
4
bash-4.3# cat checkback.conf
RUN_ARGS="--spring.config.location=/volume1/checkback/synology-config.yml"
LOG_FOLDER="/volume1/checkback"
bash-4.3#

Теперь, когда у нас есть готовая структура, мы можем начать тестирование кода. Всякий раз, когда я занимаюсь разработкой приложения, мне бы хотелось, чтобы у него были тестовые данные или снимок производственных данных. Чтобы достичь этого, вы можете прочитать блог о поддельных данных Synology для JUnit Testing .

Теперь давайте начнем кодировать. Наше приложение использует файл YAML, чтобы определить, какую папку проверять на наличие квот и какие резервные наборы необходимо проверить. Они отображаются на @ConfigurationProperties Spring. Конфиг выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
checkback:
  cron: '0 0 10 * * *'
  slack.channel: '#infra'
  quota-configs:
    - path: /volume1
      excludePattern: '^@.*'
  backup-set-configs:
    - name: Mikrotik Backups
      uri: /volume1/backupftp/mikrotik_backup
      type: DISK
      file-set:
        - name: fe-prodnet01 export
          filterPattern: '.*fe-prodnet01-.*\.rsc'
        - name: fe-prodnet11 backup
          filterPattern: '.*fe-prodnet11.*\.backup'
    - name: Exchange Backups
      uri: /volume1/pex/backups
      type: DISK
      file-set:
        - name: Exchange psts
          filterPattern: '.*\.pst'
          groupByPattern: '.*\/backups\/(\d{4}-\d{2}-\d{2})\/'
          groupByPatternHasDatePattern: 'yyyy-MM-dd'
          deletePolicy:
            deleteEmptyDirectories: true

Как видите, мы обновляем состояние каждый день в 10:00, оно определяется записью cron в YAML. Если есть какие-либо предупреждения, мы также опубликуем их на нашем канале Slack. Для этого мы используем jSlack , но существует множество других альтернатив.

Проверка квот

Чтобы проверить квоты, мы определили путь для проверки квот. По умолчанию мы исключаем каталоги, начинающиеся с «@», это каталоги, специфичные для Synology.

1
2
3
quota-configs:
  - path: /volume1
    excludePattern: '^@.*'

В Synology вы можете указать квоту для определенного общего файлового ресурса. Мы назовем эти жесткие квоты. Если вы не установили квоту (или забыли это сделать), мы по умолчанию установим квоту в 20 ГБ; это то, что мы будем называть мягкими квотами.

Чтобы проверить квоту в Synology, вы можете использовать команду btrfs :

1
2
3
4
5
bash-4.3# /sbin/btrfs qgroup show -f /volume1/share -f -r --raw
WARNING: Qgroup data inconsistent, rescan recommended
qgroupid       rfer      excl   max_rfer
--------       ----      ----   --------
0/1931   2559573532672         0 4398046511104

Есть проблема с этим подходом:

  • Как вы можете видеть из ПРЕДУПРЕЖДЕНИЯ, btrfs рассчитывает текущее использование на основе расписания, и данные противоречивы. Чтобы получить точное значение, близкое к реальному времени, вам нужно выполнить brtfs quota rescan <path> , дождаться его завершения и затем получить приблизительный размер в поле rfer .

Из-за непоследовательного вычисления значений brtfs наше приложение будет выполнять команду для каждого каталога и учитывать только max_rfer . Если max_rfer равно none , квота не была установлена ​​и по умолчанию будет 20 ГБ.

Следующий фрагмент кода Java выполняет эту команду и анализирует выходные данные.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("/sbin/btrfs", "qgroup", "show", "-f", f.toString(), "-r", "--raw");
String MAX_RFER = "";
 
LOG.info("executing command: " + f.toString());
try (InputStreamReader inputStreamReader = new InputStreamReader(processBuilder.start().getInputStream())) {
try (LineNumberReader reader = new LineNumberReader(inputStreamReader)) {
    String line;
    while ((line = reader.readLine()) != null) {
        LOG.info(reader.getLineNumber() + " : " + line);
        if (reader.getLineNumber() == 3) {
            MAX_RFER = line.split("\\s+")[3];
            break;
        }
  
    }
}
} catch (IOException ignore) {
LOG.error("Exception getting quota from btrfs command", ignore);
}
try {
  return Long.parseLong(MAX_RFER);
} catch (NumberFormatException ignore) {
  return 0;
}

Теперь, когда у нас есть предел квоты, нам просто нужно рассчитать размер каталога. Вместо того, чтобы полагаться на brtfs или du , мы просто позволим Java NIO делать эту работу.

01
02
03
04
05
06
07
08
09
10
AtomicLong totalSize = new AtomicLong();
Files.walkFileTree(f, new SimpleFileVisitor<Path>() {
  @Override
  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
      totalSize.addAndGet(Files.size(file));
      return FileVisitResult.CONTINUE;
  }
});
 
quotaStatus.used(totalSize.get());

Все, что осталось сделать, — это рассчитать оставшийся процент и отобразить его в индикаторе загрузки Bootstrap .

Форматирование байтов так, чтобы они были читаемы человеком, может быть сделано с помощью byteCountToDisplaySize из Apache Commons FileUtils . Тем не менее, этот метод плохо подходит для округления значений противоречивым способом.

В качестве альтернативы мы использовали byteunits и использовали его следующим образом, чтобы получить довольно необязательное двухточечное десятичное значение:

1
2
3
4
5
public class FileSizeUtil {
  public static String readableFileSize(long size) {
      return BinaryByteUnit.format(size,"#,##0.##");
  }
}

Если вы думаете, что мы закончили, вы забываете одно предупреждение. Чтобы выполнить команду brtfs внутри приложения, вы должны быть пользователем root. К счастью, это приложение находится в нашей внутренней сети, и риск сделать это ограничен.

Пожалуйста, не запускайте приложения как root, если ваша Synology имеет общедоступное подключение к Интернету.

Чтобы запустить приложение Spring Boot от имени пользователя root, просто выберите файл от имени пользователя root . Spring Boot сделает все остальное за вас, потому что он всегда запускает приложение под пользователем, которому принадлежит файл jar .

1
bash-4.3# chown root:root checkback.jar

Вы сделали! У нас все готово к проверке квот.

Вернитесь на следующей неделе, чтобы узнать, как контролировать наборы резервных копий.

Смотрите оригинальную статью здесь: Создание надежной системы резервного копирования

Мнения, высказанные участниками Java Code Geeks, являются их собственными.