Сохранение SQL Backup в облачном хранилище


В этой статье я расскажу, как можно настроить сохранение последних SQL бэкапов выбранных баз в облачном хранилище, используя SQL jobs.

Постановка задачи:

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

Решение:

Так как бесплатные облачные хранилища не могут похвастаться безразмерным свободным пространством, выделенным каждому пользователю, то вариант настроить бэкапы в папку, синхронизируемую с облачным хранилищем, нам не подойдет. Бэкапы за месяц туда не влезут. Нам нужно как-то определять последние бэкапы из всех файлов бэкапов для каждой базы и копировать его в отдельную папку, которая уже автоматически или задачей Windows Task или SQL Job будет синхронизироваться с облаком.

Также разумно настроить бэкап следующим образом. Полный бэкап – ночью раз в неделю или месяц, разностный (дифференциальный бэкап) каждую ночь и бэкап хвоста транзакций – каждый час. Тогда не нужно будет каждый день выгружать в облако полный бэкап, что сэкономит время и трафик. Для экстренного восстановления последней копии базы за вчерашний день, нам необходим только последний полный бэкап и один последний разностный бэкап, снятый позднее полного. Так что в облаке нам нужно хранить для каждой базы один полный бэкап и один разностный.

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

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

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

Для синхронизации локальной папки с облачным хранилищем я использовал условно бесплатную программу AllwaySync, которая умеет работать с различными облачными хранилищами (GoogleDrive, Dropbox, SkyDrive, Amazon и др.). Настройка синхронизации там интуитивно понятна, и рассказывать о ней я не буду. Единственно, что не нравится мне в этой программе, это то что она не перезаписывает файлы в облаке, а сначала удаляет, а потом записывает новый файл на место старого. Таким образом стандартная система версий файлов гугл диска не видит версии одного файла бэкапа. Конечно в программе есть своя поддержка сохранения версий файлов, но она просто копирует файлы в отдельную папку хранилища перед тем как записать новый, при этом расходуя свободное пространство хранилища. Если бы файл перезаписывался, то не расходуя место хранилища можно было бы иметь еще и историю бэкапов за последние 30 дней (на Google Drive и в Dropbox версионирование файлов поддерживается в пределах месяца).

После того как синхронизация настроена, заходим в настройки автоматической синхронизации, выбираем опцию «Использовать планировщик задач Windows» и из созданной задачи копируем строку запуска синхронизации вида («C:Program FilesAllway SyncBinsyncappw.exe» -e -m -l -s «41F5E385D231E69F376C3DA7A3C650B9»). Задачу планировщика не сохраняем, и галочку «Использовать планировщик» убираем, т.к. у нас все будет делать SQLAgent.

В наш Job со скриптом копирования бэкапов добавляем следующий шаг с типом CmdExec и вставляем туда строку запуска синхронизации через AllwaySync.

Так как сервис агента запускается под пользователем SQLSERVERAGENT, то необходимо скопировать файлы настроек AllwaySync  из папки пользователя, под которым мы делали настройки в такую же папку пользователя SQLАгента (C:UsersSQLSERVERAGENTAppDataRoamingSyncAppSettings\_SYNCAPP)

Осталось только назначить расписание выполнения задачи или включить ее в цепочку плана обслуживания следующей после выполнения бэкапов.

Код скрипта PowerShell:

#dest - Путь к папке, куда будут копироваться файлы бэкапов
#dbases - Список баз данных через запятую, без пробелов
$dest = "C:Dropbox"
$dbases = "Trade,Account"

if (-not (Test-Path $Dest))
{
Write-Warning("Destination folder is not found")
break
}

$sqlbases = "'" + $dbases.Replace(",","','") + "'"

$query = @“
SELECT
b.database_name AS DBName,
b.Type,
media.Physical_Device_name As FileName
FROM (SELECT
lb.database_guid,
MAX(lb.Backup_finish_date) AS Backup_finish_date,
lb.[type]
FROM
msdb..backupset lb
WHERE
lb.database_name IN ($sqlbases)
AND lb.[type] IN ('D','I')
GROUP BY
lb.database_guid,
lb.[type]) LastBackup
INNER JOIN msdb..backupset b ON b.Backup_finish_date = LastBackup.Backup_finish_date AND b.database_guid = LastBackup.database_guid
INNER JOIN msdb.dbo.backupmediafamily media ON b.media_set_id = media.media_set_id
ORDER BY
b.database_name,
b.Type
"@

$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "Server=(local);Database=msdb;Integrated Security=True;"
$connection.Open()

$command = $connection.CreateCommand()
$command.CommandText = $query

$result = $command.ExecuteReader()

$table = new-object “System.Data.DataTable”
$table.Load($result)

$connection.Close()

foreach ($Row In $table.Rows)
{ 
    $SourceFileName = $Row.FileName
    if (-not (Test-Path $SourceFileName -PathType Leaf))
    {
        Write-Warning("File: " + $SourceFileName + " is not found")
        Continue
    }
       
    if ($Row.Type -eq "D") {$Type = "_Full.bak"} else {$Type = "_Incr.bak"}

    $DestFileName = $dest + "" + $Row.DBName + $Type

    
    $SourceFile = Get-ChildItem -Path $SourceFileName
    if (Test-Path $DestFileName -PathType Leaf)
    {
        $DestFile = Get-ChildItem -Path $DestFileName
        if ($DestFile.LastWriteTime -ne $SourceFile.LastWriteTime)
        {
            $SourceFile.CopyTo($DestFileName, $true)
        }
        
    }
    else
    {
        $SourceFile.CopyTo($DestFileName, $true)
    } 
}

4 Comments

  1. awk

    Плюс поставил за красивый пример на PowerShell.

    Reply
  2. tank68

    Сделаю закладочку спасибо за пример

    Reply
  3. BadMadJohn

    Хочу добавить еще, что как вариант можно установить десктопную версию Google Drive и через майкрософтовскую утилиту srvany заставить его работать в качестве сервиса. Тогда не нужно будет устанавливать и настраивать скрипт для запуска программы синхронизации Allway Sync. Все обновленные файлы бэкапов, которые мы закинули скриптом в папку облачного хранилища будут автоматически закачаны в облако, и при этом будет сохраняться версионность каждого типа бэкапа для каждой базы на гугл диске глубиной в 30 дней.

    Reply
  4. MsDjuice

    Рекомендую сервис mega.nz. Вымогатель-шифровальщик Spora Ramsomware поел базу и все бэкапы, очень легко восстановилось все. Отличная функция сохранения версий файлов.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *