Стородж
Если вы уже погоняли тестовые задания в песочнице и умеете переписываться с бареосом через bconsole, то пролеземте под кат.
Ситуация
У нас просто организация, не ИТ-профиля, не хостинг. Бэкапим виртуальные машины с кластеров Hyper-V, файлы с файлопомоек и дампы баз данных, ну и ещё разные мелочи.
Почему бареос
Потому что доступен виндовый клиент. Как известно, Bareos — это драматический форк Bacula, заслуженной и проверенной. Но во время выбора бакула зажимала исходники (да и бинари) своего fd для Windows, поэтому нет. Veeam хорош, но стoит как кресло стадиона ФК «Зенит». Был DPM, но сколько мы с Антоаном из техподдержки Майкрософта с ним не боролись, любви так и не возникло.
Установка
была описана неоднократно. Кто такой директор и чем он занимается с другими демонами — можно почитать, например, здесь. Замечу только, что dir и sd крайне желательно должны быть одной версии, версия fd не так важна. По ощущениям от чейнджлогов, версию лучше иметь 16 или выше.
Базовая настройка
По DPM-овской привычке хотел создать большое задание и в него много напихать. Оказалось, что маленькие задания удобнее: при неудачном выполнении маленькое быстрее выполнится повторно и лучше пролезает через спулер (об этом дальше). На процесс восстановления размер задания не влияет, разве что задание с сотнями тысяч файлов может подтормаживать на этапе их выбора.
Hyper-V
Виртуальные машины (ВМ) работают на кластерах Hyper-V. В пределах кластера на нодах настройки fd одинаковы, хостнеймом у всех указано имя кластера. В директоре в качестве клиента тоже указан кластер со своим кластерным адресом. ВМ может переехать на другой том кластера, поэтому указываем не конкретный путь, а путь к скрипту:
FileSet {
# в названии набора файлов указываем имя виртуалки, как это удобно
Name = "VM_lamachine-fs"
Include {
# указываем имя ВМ (наличие/отсутствие "example.com" тоже важно)
File = "\\|C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -file c:/cmd/search-vm.ps1 -machine lamachine.example.com"
Options {
# диски ВМ очень хорошо жмутся
Compression = LZO
# исключаем большой лишний файл
RegexFile = ".*/Virtual Machines/.*.bin"
Exclude = yes
}
}
}
А вот c:\cmd\search-vm.ps1, который и отдаёт путь к машине:
Param(
[string]$level,
[string]$machine = "NOEXISTENTVM.example.com"
)
Import-Module failoverclusters
$backuppath = @()
$Cluster = Get-Cluster
$ClusterMachines = @()
$ClusterMachines += Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
if ($ClusterMachines.Count -eq 0 ) {
"NO MACHINES"
exit 2
}
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
$path = $VM.Path.Replace('\','/')
$backuppath += $path
foreach ($HardDrive in $VM.HardDrives){
$drivepath = $HardDrive.Path | Split-Path -Parent
$drivepath = $drivepath.Replace('\','/')
if ($drivepath -notin $backuppath){
$backuppath += $drivepath
}
}
}
$backuppath
Перед бэкапом делается снапшот, после бэкапа он удаляется, для этого есть пара чьих-то грубо допиленных скриптов.
#Copyright disclaimer:
# Copyright (C) 2015, ITHierarchy Inc (www.ithierarchy.com). ALl rights reserverd.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Param(
[string]$level,
[string]$machine = "noexist.example.com",
#[string]$prefix = "",
[int]$DayOfWeekForFullBackup = 2
)
Import-Module failoverclusters
"Processing $machine via $env:computername"
$dow = [int]$(get-date).DayOfWeek
if ($dow -eq $DayOfWeekForFullBackup){
$prefix="Weekly"
}
$DateStamp=$(((get-date)).ToString("yyyyMMddTHHmmss"))
if ($level -eq "Full"){$Backup=" Bacula -*"}Else{$Backup=" Bacula -$level*"}
#$HyperVPath="C:\Hyper-V" #Set path to your Hyper-V Machines to be backed up
#Sort out Actual Volume path to VM
#$VMDrive=$HyperVPath.Substring(0,1)
#$volume=Get-Volume $VMDrive
#$TrueHyperVPath=$($HyperVPath.Replace("$($VMDrive):\",$($Volume.path)))
#Get List of VMs
$Cluster = Get-Cluster
# let's initialize it like array (for simplier size check)
$ClusterMachines = @()
$ClusterMachines += Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
if ($ClusterMachines.count -gt 1){
"Ambiguous machine name"
exit 2
}
if ($ClusterMachines.count -ne 1){
"Machine not found: absent, not in failover cluster or something"
exit 2
}
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
write-host "Working on VM $($vm.Name) @ '$($vm.Path)'"
$CurrentSnapShots = $VM | Get-VMSnapshot
foreach ($SnapShot in $CurrentSnapShots){
if ($SnapShot.Name -like ("$($prefix)Backup*")){
write-host "Removing VM Checkpoint '$($SnapShot.Name)'"
$SnapShot | Remove-VMSnapshot # -ComputerName $ClusterMachine.OwnerNode
$LoopCount=0
do {
Write-host "Waiting for snapshot '$($SnapShot.name)' to delete..."
Start-Sleep -s 10
$LoopCount=$LoopCount+1
}while ($VM.Status -eq "Merging disks" -and $LoopCount -lt 30)
}
}
$label = "$($prefix)Backup-$level-$DateStamp"
write-host "Creating Checkpoint $label ($($VM.Name))"
$VM | Checkpoint-VM -SnapshotName $label
}
Удаление:
#Copyright disclaimer:
# Copyright (C) 2015, ITHierarchy Inc (www.ithierarchy.com). ALl rights reserverd.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Param(
[string]$level,
[string]$machine = "noexist.example.com",
[string]$vmmserver = "vldvmm.example.com"
)
Import-Module failoverclusters
$Cluster = Get-Cluster
$ClusterMachines = Get-ClusterResource -Cluster $Cluster | where { $_.ResourceType -like "Virtual Machine" } | where { $_.Name -like "*$machine"} | `
select -Property OwnerNode,Name, @{
Name ="VmID";Expression ={ (Get-ClusterParameter -Cluster $Cluster -InputObject $_ | where { $_.Name -eq "VmID" } | select -Property Value).Value }
}
# FIXME foreach по идее лишний
foreach ($ClusterMachine in $ClusterMachines){
$VM = Get-VM -ComputerName $ClusterMachine.OwnerNode -Id $ClusterMachine.VmID
write-host "Working on VM $($vm.Name) @ '$($vm.Path)'"
$CurrentSnapShots = $VM | Get-VMSnapshot
foreach ($SnapShot in $CurrentSnapShots){
if ($SnapShot.Name -like ("Backup*")){
write-host "Removing VM Checkpoint '$($SnapShot.Name)'"
$SnapShot | Remove-VMSnapshot # -ComputerName $ClusterMachine.OwnerNode
$LoopCount=0
do {
Write-host "Waiting for snapshot '$($SnapShot.name)' to delete..."
Start-Sleep -s 10
$LoopCount=$LoopCount+1
}while ($VM.Status -eq "Merging disks" -and $LoopCount -lt 30)
}
}
}
Снапшот можно не удалять, тогда получится делать инкрементальные бэкапы (в скрипте есть зачатки такой функциональности — DayOfWeekForFullBackup).
Кассеты
Мы используем ленточные библиотеки: такая
ls /dev/tape/by-id/
, с суффиксом "-nst" — пишущий драйв, без оного — робот-авточейнджер.Что касается использования двух приводов для параллельной записи в один пул (набор томов): это сократило бы время записи, но делать так не стали. В выделенное окно бэкапов и так вписываемся, а вот расход плёнки может увеличиться. Но если кто захочет параллельную запись, то не забудьте
Prefer Mounted Volumes
установить в No
. Писать же в два разных пула можно без проблем и оверхеда.Scratch-пулы. Хочу обратить на них внимание: из них бареос берёт кассеты для добавления в другие пулы, в которые он собирается писать. Незнакомую кассету без метки бареос в рабочий пул добавлять не станет. Поэтому все новые ленты добавляем в пул Scratch:
label barcodes storage=mylittlestorage slot=1 pool=Scratch
Можно добавить не в Scratch, а сразу в рабочий пул, но если пулов несколько, то не всегда можно предсказать, сколько кассет в каком понадобится. Поэтому пусть берёт сам по необходимости.
Размер блоков и файлов нужно поставить побольше, это благотворно скажется на скорости лент. «If you are con?guring an modern drive like LTO-4 or newer, you probably will want to set the Maximum File Size to 20GB», так что не скромничайте.
Чтобы у бареоса не возникло искушения что-нибудь записать на кассету, которая уже находится в далёком сейфе, лучше перед выемкой сменить ей статус с Append на Used:
update volume=KYF389L6 volstatus=Used
Этой же командой можно менять другие свойства кассеты, скажем, переместить в другой пул:
update volume=KYF389L6 pool=YetAnotherPool
Кассету легко выкрасть (ну, легче, чем IBM DS8800), поэтому данные крайне желательно зашифровать. Можно сделать это средствами самой писалки, но я люблю софтовые решения как более универсальные и гибкие. Просто не забудьте.
Бывает, что бареос уже когда-то писал метку на кассету, но записи об этой кассете в базе не имеет. Второй раз
label
не сработает («error: already labeled»), есть команда add
, но в моём случае она приводила к проблемам, после неё использовать кассету не получалось. На этот случай родился такой однострочник (выполняется в bash на сервере sd, сам bareos-sd должен быть остановлен):mtx -f /dev/sg10 load 25 && mt -f /dev/st0 rewind && mt -f /dev/st0 weof && mt -f /dev/st0 rewind && mtx -f /dev/sg10 unload
Если не даёт сделать unload, то предварительно
mt -f /dev/st0 offline
Спулинг
Это когда данные пишутся сначала на SSD (или хотя бы быстрый HDD), а потом уже на ленту. По сравнению с последовательным выполнением, сокращается время работы стриммера (он пишет быстрее) и общее время выполнения заданий, если их много. Если задание одно, то время использования привода также сократится, но общее время выполнения задания вырастет.
Чтобы работало, сначала на стороне sd нужно указать расположение и размер спулера:
Device {
Name = Drive-0
...
# для спулинга
Maximum Concurrent Jobs = 20
Spool Directory = /mnt/backup/spool
Maximum Spool Size = 1950 G
Maximum Job Spool Size = 1200 G
}
а затем уже включить для конкретных заданий:
JobDefs {
Name = "SundayTape"
...
Spool Data = Yes
}
У меня эта директива в шаблоне «ленточного» задания, а для «дисковых» заданий спулинг практически бесполезен.
Принципы такие:
- задание может читаться из источника и писаться в спулер (далее «чтение») или читаться из спулера и писаться на ленту (далее «запись»). Одновременно то и другое — нет, для этого понадобится разбить задание на два. Поэтому я выше рекомендовал делать задания поменьше.
- желательно чтобы писалка писала с максимальной скоростью, для этого в спулере всегда должны быть готовые к записи данные (в status storage=my-little-storage они отмечены флажком spool_wait).
- нужно, чтобы спулер не переполнялся. Если переполнится, то все данные из него (сразу всех заданий!) захотят записаться на ленту (задеспулиться ), вызывая фрагментацию на ленте. Какие-нибудь 300 Гбайт могут размазаться по трём 2,5 Тбайтным лентам, а оно нам не надо.
Размер спулера и количество одновременных заданий зависят от общего количества заданий, размеров заданий, скорости чтения данных (которая может упираться в скорость сети или спулера), скорости записи ленты, соотношений размеров и скоростей разных заданий, человеческих желаний (побыстрее получить результат, или поменьше занимать писалку, или поменьше тратить кассет). Всё это можно связать адовым матаном, но я рекомендую настроить спулинг как бог на душу положит, потому что даже упрощённые правила непросты:
- нужно выбрать количество одновременно запущенных заданий, чтобы в сумме они давали данных больше, чем пропускная способность ленты. Скорости разных источников могут сильно отличаться, даже скорость одного источника может сильно меняться. Например, fixed vhdx может отдавать 100 Мбайт/с в начале и 500 кБайт/с в конце, когда fd отдаёт пожатые нули. Это затрудняет расчёт, но c’est la vie, берите с запасом.
- в идеале, спулер должен вмещать целиком все одновременно выполняемые задания. Но не у всех есть столько SSD, а скорость HDD может оказаться меньше скорости какого-нибудь LTO-6.
- пока данные из одного источника ещё читаются (спулятся), другие данные могут уже записаться и освободить место в спулере, за счёт этого спулер можно сократить. Тут чем больше разница размеров заданий, тем лучше (если не получается все задания сделать маленькими).
- если завершились все задания, кроме одного самого большого, то пусть оно спулится/деспулится сколько угодно, фрагментации это уже не сделает.
- если вы хотите расставить свои задания в некотором порядке (скажем, сначала запустить пару маленьких и самое большое, а потом уже все остальные — это выгодно по времени), то задайте им разные расписания или разные приоритеты (но в этом случае не забудьте
Allow Mixed Priority
)
Количество одновременно выполняемых заданий ограничивается много где, ищите в документации «Concurrent Jobs =». Мне оказалось удобно везде поставить большое число с запасом, и ограничивать нужным числом на конкретном устройстве (sd device).
Про файлы
Линуксовая привычка — лезть во внутренности, расковыривать и грепать. То же самое хотелось и с файлами-томами бареоса, чтобы можно было найти нужный том и восстановить даже при неработающем директоре. Для этого попробовал на каждое задание создавать новый файл с именем, содержащим имя задания. Пришлось удалять устаревшие тома скриптом по крону, а ещё следить, чтобы у каждого тома было задание в базе и наоборот. Бареос быстро начал обрастать жуткими костылями, решено было отказаться от человекочитаемого именования, использовать бессмысленные имена и Recycle (очистка и повторное использование файла для другого задания). Всё-таки без директора никуда, при потере серверной в первую очередь нужно восстанавливать именно его.
А ещё IBM рекомендует хранить одно задание в одном файле, и пока что я с ними согласен.
Мониторинг
Некоторые отчётные удобства на улице^W^W тоже пришлось добавить скриптами. Самым востребованным оказался скрипт, возвращающий статус последнего запуска задания.
#!/bin/bash
RED='\033[0;31m'
NC='\033[0m' # No Color
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
JOBS=`su - postgres -c "psql -d bareos -c \"WITH summary AS (
SELECT name,jobstatus,jobid,
ROW_NUMBER() OVER(PARTITION BY name ORDER BY starttime DESC) AS rk
FROM job p WHERE starttime > current_date - INTERVAL '5 days')
SELECT s.* FROM summary s WHERE s.rk=1;\"" | grep "1$" | sed 's/ //g'`
#echo "$JOBS"
for job in $JOBS; do
jobstatus=`echo $job | cut -d '|' -f2`
jobname=`echo $job | cut -d '|' -f1`
jobid=$(echo $job | cut -d '|' -f3)
if [ "$jobstatus" == "R" ]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$YELLOW running$NC ($jobstatus)"
elif [ "$jobstatus" == "W" ]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$YELLOW warning$NC ($jobstatus)"
elif [ "$jobstatus" == "T" ]; then
if [[ $1 == "printall" ]]; then
printf "%-30s" "$jobname ($jobid)"
echo -e "$GREEN OK$NC ($jobstatus)"
fi
else
printf "%-30s" "$jobname ($jobid)"
echo -e "$RED failed$NC ($jobstatus)"
fi
done
Первоначальный вариант скрипта проверял ещё и факт шифрования, но это оказалось перебдением. Если возникают проблемы с шифрованием, то задание фатально завершается, что будет видно опять же по статусу.
#!/bin/bash
JOBS=`su - postgres -c "psql -d bareos -c \"
SELECT name,starttime,jobstatus
FROM job p WHERE starttime > current_date - INTERVAL '62 days' AND name = '$1'
ORDER BY starttime DESC LIMIT 1;\"" | sed 's/ //g' | grep "|.$"`
for job in $JOBS; do
jobname=`echo $job | cut -d '|' -f1`
jobstatus=`echo $job | cut -d '|' -f3`
if [ "$jobstatus" == "E" ] || [ "$jobstatus" == "f" ]; then
#echo "Job $jobname failed ($jobstatus)."
echo "3"
exit
elif [ "$jobstatus" == "W" ]; then
#echo "Job $jobname with warning ($jobstatus)."
echo "1"
exit
elif [ "$jobstatus" != "T" ] && [ "$jobstatus" != "R" ]; then
#echo "Job $jobname not ok ($jobstatus)."
echo "2"
exit
elif [ "$jobfiles" == 0 ] || [ "$jobbytes" == 0 ] ; then
#echo "Job $jobname is empty."
echo "4"
exit
else
echo "0"
exit
fi
done
Скрипт для дискаверинга (LLD) приколочен к формату вывода bconsole и легко может сломаться, но пока работает. И JSON лепится руками, но пока тоже работает.
#!/bin/bash
FIRST=true
JOBS=$(echo "show jobs" | bconsole | grep "^ *Name = \|Enabled = no" | sed 'N;/\n Enabled = no/d;P;D' | grep -v -e "-test\"$" | cut -d'=' -f 2 | grep -o "[a-zA-Z0-9_-]*" )
echo '{
"data": ['
for job in $JOBS; do
if [ "$FIRST" = false ]; then
echo -n ","
fi
FIRST=false
echo ""
echo " {"
echo " \"{#JOBNAME}\": \"$job\""
echo -n " }"
done
echo '
]
}'
А ещё я люблю stacked-графики в заббиксе, вот, например, занятый разными заданиями объём пленки:
Видно, что синее задание пора поделить на несколько маленьких.
Приятные мелочи
- С самого начала пользовался командой
status storage=
, но почему-то не приходило в голову сделатьstatus director
. Там обнаружилась удобная сводка (а еслиwatch "echo 'status director' | bconsole"
, то практически дашборд), своей простотой особенно полезная для операторов-кассетоменятелей. - В bconsole работают башевские Ctrl+R (поиск по истории команд), Ctrl+W (удаление слова) и тому подобное.
Будущие свершения
- Бутстрапы. Если при катастрофе вместе с бизнес-серверами будет потерян директор бареоса, то админа вызовут в кирдычную^W^W^W^W восстановление продакшен-серверов может затянуться. Чтобы быстро восстановить директора, директор бэкапит сам себя и шлёт мне на почту бутстрапы. Но я не знаю, что с ними делать, инструкции не особо внятные, тестить пока не тестил. Поэтому бареос в конце сессии бэкапов ещё тупо бэкапит виртуалку с собой и тут же восстанавливает её на другой сервер. И ещё есть запасной директор с копией конфигов и репликой постгреса. Но бутстрапы надо будет обязательно освоить.
- Сделать нормальную миграцию. Есть такая теоретически крутая штука — миграция: скажем, держим бэкапы за сегодня и вчера на дисках, а потом они переезжают на ленты. Но красиво это сейчас не работает. Бареос не станет писать несколько файлов-томов на одну кассету (которая тоже том). Он хочет писать каждый файл на отдельную кассету. Это логично, но крайне непрактично, ведь у нас в файле хранится одно задание, а задания маленькие, помните?
- Отвязать пул от библиотеки. У меня библиотек две (одна из них двухприводная), и запись в каждый пул привязана к конкретному девайсу (восстанавливать данные можно на любом девайсе, с этим проблем нет). В описании пула можно указать несколько девайсов, тут вопрос времени: нужно сесть, сделать и потестить.
- Заставить работать lz4 на linux-fd. Что-то собирал отсюда, но с ходу не заработало, пока не разобрался.
Задавайте вопросы, софтина чёткая, хотя и с характером, мне хочется поспособствовать её распространению.
И не забывайте проверять свои бэкапы.
Комментарии (10)
ewgenik
07.09.2017 17:51+1Еще есть хорошая идея к уведомлению о завершении задания прикреплять вывод консольной команды «messages». Стандартные макросы в письме (%c %d %e %h и т.д.) не дают достаточной информации. А вот листинг «messages» позволит сразу в отчете видеть практически всю инфу о выполненном задании. Как это реализовать — вариантов уйма.
ingvarhost
07.09.2017 17:51+1Главная проблема Бареоса на данный момент — отсутствие обновлений. В свободный доступ выкладывается только начальная версия, а вот обновления с багфиксами только по платной подписке. Ну и в добавок — слишком переусложненная конфигурация, очень тяжелая настрока SSL, остутствие дедупликации.
Tabletko
07.09.2017 17:51Используете ли вы Always Incremental backup?
muon Автор
07.09.2017 17:59Мы — нет. Я пока не понял, что это и нужно ли нам оно.
Мне нравится концепция декрементального бэкапа, но это не про бареос.FlashHaos
07.09.2017 23:16Такие бекапы очень хороши — забираешь инкрементал, а уже на стороне хранилища из него и предыдущего полного лепится синтетический полный. Уменьшает объем передаваемых данных и, соответственно, окно бекапа. Сплошные плюсы, кроме того, что такая технология не работает с лентами в силу своей специфики.
FlashHaos
07.09.2017 23:25+1Очень рекомендую писать с нуля или собирать из модулей единую систему мониторинга и анализа СРК, включив туда и хранилки и процессы бекапа и клиенты и устройства РК. Если грамотно прописать взаимосвязи и настроить аналитику — можно удобно из одного места видеть всё. К примеру, я у себя написал достаточно педальную функцию, которая смотрит на текущий бекап и сравнивает его длительность с средним по последним десяти. Если бекап неожиданно идёт заметно дольше или выполнен слишком быстро — вывести тревожное сообщение. Медленный бекап обычно значит, что где-то в инфраструктуре узкое место (и если в одном интерфейсе видно состояние хранилки и медиасервера — обычно сразу ясен ответ), а слишком быстрый бекап — что мы забираем сегодня не тот объем, что всегда (например не успел создаться дамп или база уехала с виртуалки).
Касательно software шифрования — какие преимущества пред хардварным? Софтваре будет жрать ресурсы сервера, а хардваре — грузить специально обученный процессор на ленточном приводе.
Еще я не очень понял, насчет «Бареос не станет писать несколько файлов-томов на одну кассету». Это как? Один бекап — одна лента? У себя в СРК я с таким никогда не сталкивался.muon Автор
09.09.2017 11:51Еще я не очень понял, насчет «Бареос не станет писать несколько файлов-томов на одну кассету». Это как?
Это про миграцию: бареос может перенести данные из одного пула в другой, например, с дисков на ленту. Но он не занимется объединением томов. Если на дисках данные лежали в нескольких томах (файлах), то он не соберёт их в один новый том (ленту).
FlyingDutchman
Увы, так и не сумели подружить бареос и оракловский RMAN-бэкап. Нигде нет внятных доков на эту тему, а стандартные оракловские скрипты не видят SBT-драйвера