Эта статья не для ознакомления с bacula. Она для тех, кто вплотную
занимается ее внедрением или эксплуатацией.
Для ознакомления см. раздел Ссылки.
Мы будем говорить конкретно про версию bacula 1.38.11-3. Скорее всего
сказанное будет относиться и ко всей ветке 1.38.
Само собой автор не дает никаких гарантий безопасности ваших данных.
В документации по Bacula написано, что не рекомендуется выполнять
параллельные задания. Вернее, выполнять их можно, но только после
тщательного тестирования, чем мы и займемся.
Цели и задачи
Мы соберем тестовую конфигурацию для выполнения параллельных заданий.
Рассмотрим какие параметры с этой точки зрения наиболее важны. Данный
материал послужит для более глубокого понимания функционирования
системы.
Теоретические основы
В документации сказано следующее.
Running Concurrent Jobs
По умолчанию Bacula не сконфигурирован для параллельного выполнения
заданий.
Значения по умолчанию:
bacula-dir.conf
Director {
Maximum Concurrent Jobs = 1
}
bacula-fd.conf
FileDaemon {
Maximum Concurrent Jobs = 20
}
bacula-sd.conf
Storage {
Maximum Concurrent Jobs = 20
}
Если вы не предполагаете одновременно выполнять более 20 заданий, то
все изменения нужно вносить только в файл bacula-dir.conf. Каждый
параметр должен быть установлен правильно, согласно вашим
потребностям, иначе ваши задания могут быть выполнены по одному.
Например, если вы хотите, чтобы два различных задания выполнили
одновременное копирование одного и того же Клиента на то же самое
Storage, то они выполнятся параллельно, только если вы установили
Maximum Concurrent Jobs, больше чем один в ресурсах Director, Client,
и Storage в bacula-dir.conf Изменения в ресурсе Job необязательны.
bacula-dir.conf
Director {}
Job {}
Client {}
Storage {}
Настоятельно рекомендуется тщательно проверить выполнение параллельных
резервных копий, включая полное восстановление с них, прежде, чем
принять это в дальнейшую эксплуатацию.
Пример:
# Bacula Director Configuration file -- bacula-dir.conf
Director {
Name = rufus-dir
Maximum Concurrent Jobs = 4
...
}
Job {
Name = "NightlySave"
Maximum Concurrent Jobs = 4
Client = rufus-fd
Storage = File
...
SpoolData = yes # можно добавить к заданиям, кот. могут
# параллельно писать в один Storage
}
Client {
Name = rufus-fd
Maximum Concurrent Jobs = 4
...
}
Storage {
Name = File
Maximum Concurrent Jobs = 4
...
}
Помните: в данный момент времени на любом из устройств (Device) может
быть смонтирован только один Том (Volume). Поскольку и для дисковых
устройств Bacula придерживается принципа ленты (т.е. в данный момент
времени на устройстве может быть смонтирована только одна лента). Если
вы хотите одновременно писать на множество томов на множестве
устройств, то вы должны определить несколько Device в bacula-sd.conf
Из-за выполнения параллельных Заданий формат Volume становится намного
более сложным, следовательно, восстановление может быть намного
дольше, т.к. Bacula должен будет делать сортировку чередующихся блоков
данных, записанных в Том из множества одновременных заданий. Этого
можно избежать если каждое одновременно выполняющееся задание будет
писать в различные тома или при использовании спулинга, т.е. помещения
данных в очередь (Spool), т.е. сначала данные попадут в очередь на
диск одновременно, а затем каждый буферный файл будет последовательно
записан на определенный том.
Приоритеты
Для каждого Задания можно назначить приоритет выполнения. Однако в
документации дается весьма запутанное объяснение того, что такое
приоритет, поэтому без тестирования на практике вам не обойтись.
Priority = number
Значение по умолчанию - 10.
Эта директива управляет порядком выполнения заданий. Чем выше число,
тем ниже приоритет задания. Все поставленные в очередь задания с
приоритетом 1 выполнятся перед поставленными в очередь заданиями с
приоритетом 2 и так далее, независимо от первоначального планирования.
Приоритет затрагивает только ожидающие задания, которые поставлены в
очередь, но не задания, которые уже выполняются.
Если вы хотите выполнять задания параллельно, то вы должны помнить:
* чтобы выполнять параллельные задания, вы должны установить Maximum
Concurrent Jobs = 2 в 5 или 6 различных местах: в bacula-dir.conf
в ресурсах Job, Client, Storage; в bacula-fd в FileDaemon (или
Client) ресурсе, и в bacula-sd.conf в ресурсе Storage. Если к.-л.
из них будет отсутствовать, то это принудит задания выполняться по
одному.
* Bacula одновременно выполняет задания только одного приоритета.
Т.е. не будет одновременно выполнять задания с приоритетом 1 и с
приоритетом 2.
* Если Bacula выполняет задание с приоритетом 2 и запланировано
новое задание с приоритетом 1, то оно будет ждать завершения
задания с приоритетом 2, даже если параметр Maximum Concurrent
Jobs допускает одновременное выполнения двух заданий.(Обратите на
это особое внимание)
* Пока есть более высокое приоритетное задание, ждущее выполнения,
никакие новые низкоприоритетные задания не начнутся, даже если
Maximum Concurrent Jobs допускает одновременное выполнения двух
заданий. Это гарантирует, что высокоприоритетные задания будут
выполнены как можно скорее. Если вы имеете несколько заданий
различных приоритетов, то лучше всего запустить их в одно время,
потому что Bacula будет исследовать их по одному. Если Bacula
запускает сначала более низкоприоритетное задание, то оно
выполнится раньше высокоприоритетных заданий. Для решения проблемы
запускайте высокоприоритетные задания за несколько секунд до
начала низкоприоритетных. Таким образом ваша схема приоритетов
будет работать правильно.
Практическая реализация
Теперь мы будем строить систему с параллельным выполнением заданий, с
учетом приоритетов и с использованием спулинга.
Полные файлы конфигурации приведены ниже.
bacula-dir.conf
Director {
Name = "main.dir"
DIRport = 9101
QueryFile = "/etc/bacula/query.sql"
WorkingDirectory = /arc/temp
PidDirectory = "/var/run"
Maximum Concurrent Jobs = 100
Password = "123"
Messages = Daemon
}
Storage {
Name = "StorageFile1"
Address = localhost
SDPort = 9103
Password = "123"
Device = "devFileStorage1"
Media Type = File1
Maximum Concurrent Jobs = 100
}
Storage {
Name = "StorageFile2"
Address = localhost
SDPort = 9103
Password = "123"
Device = "devFileStorage2"
Media Type = File2
Maximum Concurrent Jobs = 100
}
Job {
Name = "restore.files"
Type = Restore
Client = "local.fd"
FileSet = "Full Set"
Storage = StorageFile1
Pool = "pool.test1"
Messages = Standard
Replace = ifnewer
Where = /arc/restore
Maximum Concurrent Jobs = 100
Priority = 10
Write Bootstrap = "/var/bacula/test11.bsr"
RunBeforeJob = "/etc/bacula/scripts/restore_before.sh"
}
# List of files to be backed up
FileSet {
Name = "Full Set"
Include {
Options {
signature = MD5
}
File = /tmp
}
}
Client {
Name = "local.fd"
Address = localhost
FDPort = 9102
Catalog = MyCatalog
Password = "123"
Maximum Concurrent Jobs = 100
}
Catalog {
Name = MyCatalog
dbname = bacula; user = bacula; password = ""
}
Messages {
Name = Standard
mailcommand = "/usr/sbin/bsmtp -h localhost -f "localhost" -s "Bacula: %t%e : %n (%c) %l" %r"
operatorcommand = "/usr/sbin/bsmtp -h localhost -f "localhost" -s "Bacula: Intervention needed : %j" %r"
mail = root@localhost = all, !skipped
operator = root@localhost = mount
console = all, !skipped, !saved
append = "/var/bacula/log" = all, !skipped
}
Messages {
Name = Daemon
mailcommand = "/usr/sbin/bsmtp -h localhost -f "localhost %r" -s "Bacula daemon message" %r"
mail = root@localhost = all, !skipped
console = all, !skipped, !saved
append = "/var/bacula/log" = all, !skipped
}
Pool {
Name = "pool.test1"
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 1 days
Accept Any Volume = yes
LabelFormat = "pool.test1."
}
Pool {
Name = "pool.test2"
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 2 days
Accept Any Volume = yes
LabelFormat = "pool.test2."
}
Job {
Name = "file1-to-pool1"
Type = Backup
Level = Full
Client = "local.fd"
FileSet = "file.set.test1"
Storage = StorageFile1
Messages = Standard
Pool = "pool.test1"
Write Bootstrap = "/var/bacula/test11.bsr"
RunBeforeJob = "/etc/bacula/scripts/test1_before.sh"
SpoolData = yes
Maximum Concurrent Jobs = 100
Priority = 10
}
Job {
Name = "file2-to-pool2"
Type = Backup
Level = Full
Client = "local.fd"
FileSet = "file.set.test2"
Storage = StorageFile2
Messages = Standard
Pool = "pool.test2"
Write Bootstrap = "/var/bacula/test22.bsr"
RunBeforeJob = "/etc/bacula/scripts/test2_before.sh"
SpoolData = yes
Maximum Concurrent Jobs = 100
Priority = 10
}
Job {
Name = "file1-to-pool2"
Type = Backup
Level = Full
Client = "local.fd"
FileSet = "file.set.test1"
Storage = StorageFile2
Messages = Standard
Pool = "pool.test2"
Write Bootstrap = "/var/bacula/test12.bsri"
RunBeforeJob = "/etc/bacula/scripts/test1_before.sh"
SpoolData = yes
Maximum Concurrent Jobs = 100
Priority = 10
}
Job {
Name = "file2-to-pool1"
Type = Backup
Level = Full
Client = "local.fd"
FileSet = "file.set.test2"
Storage = StorageFile1
Messages = Standard
Pool = "pool.test1"
Write Bootstrap = "/var/bacula/test21.bsr"
RunBeforeJob = "/etc/bacula/scripts/test2_before.sh"
SpoolData = yes
Maximum Concurrent Jobs = 100
Priority = 10
}
bacula-sd.conf
Storage {
Name = "Storage1"
SDPort = 9103
WorkingDirectory = /arc/temp
Pid Directory = "/var/run"
Maximum Concurrent Jobs = 100
}
Director {
Name = "main.dir"
Password = "123"
}
Device {
Name = "devFileStorage1"
Media Type = File1
Archive Device = /arc/dev
LabelMedia = yes;
Random Access = Yes;
AutomaticMount = yes;
RemovableMedia = no;
AlwaysOpen = no;
Spool Directory = /arc/spool
}
Device {
Name = "devFileStorage2"
Media Type = File2
Archive Device = /arc/dev
LabelMedia = yes;
Random Access = Yes;
AutomaticMount = yes;
RemovableMedia = no;
AlwaysOpen = no;
Spool Directory = /arc/spool
}
Messages {
Name = Standard
director = "main.dir" = all
}
bacula-fd.conf
Director {
Name = "main.dir"
Password = "123"
}
FileDaemon {
Name = "local.fd"
FDport = 9102
WorkingDirectory = /arc/temp
Pid Directory = /var/run
Maximum Concurrent Jobs = 100
}
Messages {
Name = Standard
director = "main.dir" = all, !skipped
}
restore_before.sh
#!/bin/bash
sleep 180
exit 0
test1_before.sh
test2_before.sh
#!/bin/bash
sleep 180
exit 0
Обратите внимание на то, что все приоритеты заданий одинаковы (как я
уже говорил, в документации дается весьма запутанное объяснение того,
что такое приоритет, поэтому без тестирования на практике вам не
обойтись).
Скрипты RunBeforeJob нужны только для имитации долгой работы, чтобы
успеть запустить с консоли нужные задания и проверить их статус.
Если вы хотите очистить всю конфигурацию, воспользуйтесь скриптом:
Запустите по порядку все задания, кроме restore.files.
Затем дайте команду:
* status dir
вы должны увидеть примерно следующее:
Running Jobs:
JobId Level Name Status
1 Full file1-to-pool1 is running
2 Full file2-to-pool2 is running
3 Full file1-to-pool2 is running
4 Full file2-to-pool1 is running
Т.е. одновременно выполняются множество заданий резервного
копирования. Что и требовалось.
Тест 2 (успешный)
Положите какой-нибудь небольшой файл в каталог /arc/test/1
Сначала запустите задание file1-to-pool1. Запомните его JobId.
После того как оно успешно завершится, запустите задание
file2-to-pool2.
Тут же немедленно запустите задание для восстановления файлов
restore.files. Укажите JobId уже выполнившегося задания file1-to-pool1
и Bootstrap: /var/bacula/test11.bsr
Затем дайте команду:
* status dir
вы должны увидеть примерно следующее:
Running Jobs:
JobId Level Name Status
2 Full file2-to-pool2 is running
3 restore.files is running
Т.е. мы одновременно выполняем резервное копирование и восстановление.
Обратите внимание на то, что резервное копирование и восстановление
работают с разными Storage.
Тест 3 (неуспешный)
Теперь попробуем поработать как и в тесте #2, но с одним и тем же
Storage.
Сначала запустите задание file1-to-pool1. Запомните его JobId.
После того как оно успешно завершится, опять запустите задание
file1-to-pool1.
Тут же немедленно запустите задание для восстановления файлов
restore.files. Укажите JobId уже выполнившегося задания file1-to-pool1
и Bootstrap: /var/bacula/test11.bsr
Running Jobs:
JobId Level Name Status
2 Full file1-to-pool1 is running
3 restore.files is waiting on max Storage jobs
Как видим, резервное копирование и восстановление с одним и тем же
Storage параллельно выполняться не хочет.
Тест 4 (неуспешный)
Теперь попробуем поработать как и в тесте #2, но повысим приоритет
задания на восстановление - restore.files.
Мы наивно полагаем, что задание на восстановление должно иметь
наивысший приоритет и должно выполняться вне очереди, т.к. в это время
уже что-то нехорошее случилось и надо срочно восстанавливать данные.
Running Jobs:
JobId Level Name Status
1 Full file1-to-pool1 is running
2 restore.files is waiting for higher priority jobs to finish
Как видим, восстановление не выполняется так, как нам бы хотелось.
В документации так и написано: "если Bacula уже выполняет задание с
приоритетом 10 и запланировано новое задание с приоритетом 9, то оно
будет ждать завершения задания с приоритетом 10, даже если параметр
Maximum Concurrent Jobs допускает одновременное выполнения двух
заданий". Немного странно, не так ли?