Привет. Некоторое время назад в официальной русской группе Windows Azure на Facebook у одного из участников возник вопрос — а как можно автоматизированно создавать бекапы для баз данных Windows Azure SQL Database, куда-нибудь их выкладывать и потом скачивать по запросу.
Действительно, «из коробки» такого функционала нет, поэтому надо писать самим. Там же группе на Facebook была дана ссылка, как можно снять бекап с базы данных, используя Power Shell и библиотеку Microsoft.SqlServer.Dac.dll, которая входит, по всей видимости, в постаку SQL Server Management Studio и/или Visual Studio (честно говоря я не отследил, откуда именно она взялась на моей машине). Используя эту библиотеку можно получить BACPAC-пакет, который является практически полным бекапом базы данных. По крайней мене структуру и данные восстановить с его помощью не представляет никакого труда.
Эта статья дает ответ на первый вопрос — как снять бекап с БД, расположенной в облаке Windows Azure. Однако абсолютно не отвечает на два других — как выложить результат в Blob Storage и как все это автоматизизировать. Очевидным решением станет вариант с размещением в облаке спциального сервиса, который бы раз в определенное время запускал бы процесс снятия бекапа и копирования его в хранилище. Его-то я и решил написать, чтобы олегчить жизнь как себе, так и коллегам.
На самом деле весь функциональный код умещается в совсем уж неприлично малое количество строк. Ниже я приведу вырванный из контекста, однако полностью покрывающий процесс бекапирования и размещения в хранилище кусок кода:
public void Execute(IJobExecutionContext context) { // Retrieving parameters from trigger var properties = context.Trigger.JobDataMap["JobProperties"] as ServiceExecutionProperties; var tempFile = Path.GetTempFileName(); var errorMessage = ""; try { // Trying to create BACPAC package var service = new DacServices(properties.DbConnectionString); service.ExportBacpac(tempFile, properties.DatabaseName); } catch (Exception ex) { // Something went wrong errorMessage = ex.Message; if (ex.InnerException != null) errorMessage += Environment.NewLine + "Inner: " + ex.InnerException.Message; } // If bacpac file still doesn't exist - error if (!File.Exists(tempFile)) errorMessage += Environment.NewLine + "BACPAC file was not created."; try { // Publish to Windows Azure Blob Storage var acc = new StorageCredentialsAccountAndKey(properties.StorageAccountName, properties.StorageKey); var storageAccount = new CloudStorageAccount(acc, true); var client = storageAccount.CreateCloudBlobClient(); var container = client.GetContainerReference(properties.BlobContainerName); container.CreateIfNotExist(); // Blob has .bacpac extension if everything was good // and .error extension if there was an exception var blob = container.GetBlockBlobReference( string.Format("{0}_{1}UTC{2}", properties.DatabaseName, DateTime.UtcNow.ToString("yyyyMMdd_HHmmss"), string.IsNullOrEmpty(errorMessage) ? ".bacpac" : ".error")); if (string.IsNullOrEmpty(errorMessage)) { // Upload file if exists blob.UploadFile(tempFile); File.Delete(tempFile); } else { // Upload error message blob.UploadText(errorMessage); } } catch { } }
Видно, что весь процесс получения бекапа умещается в строках 10 и 11. Остальная часть кода — уже довольно известная работа с хранилищем Windows Azure Blob Storage.
На этом можно было бы и заканчивать, оставив читателя на едине с мыслями, а как же все это хозяйство заставить выполняться по расписанию. Однако я все расскажу об еще одной удобной штуке. Около года назад в поле моего зрения попала довольно неплохая библиотека Quartz.NET, которая позволяет выполнять код по расписанию, заданному в стиле cron. С ее помощью очень удобно выставить нужное нам расписание создания бекапов, запустить планировщик в нашем сервисе и просто смотреть, как все работает.
Помимо сервиса для Windows Azure Worker Role я также сделал простой Windows Service, поскольку нет абсолютно никакой разницы, откуда будет запущен процесс бекапирования. Особенно если у вас уже есть работающий физический сервер и вам не хочется лишний раз создавать дополнительные облачные инстансы.
Весь код я выложил в CodePlex и GitHub в виде Open Source проектов. Кому надо — пользуйтесь на здоровье.
P.S. Мне не очень нравится текущая реализация бекапирования и хранения с промежуточным этапом в виде временного файла. Понято, что если БД будет больших размеров, то большой файл бекапа может либо замусорить наше облако, либо не создасться вовсе. Гораздо больше мне нравится идея использовать потоки. Метод DacSerivce.ExportBacpac имеет перегрузку, которая принимает Stream в качестве параметра. Также CloudStorageBlockBlob имеет метод OpenWrite, возвращающий Stream. Однако мне не удалось заставить работать их в паре. Использование потока из блоба вызывает ошибку при экспорте, которая звучит как «Stream does not support seeking.». Может у кого-то из читателей найдется ответ, как лучше все это провернуть. Ну или успокоит меня, что временные файлы — вполне себе гуд.
Если это продакшен база, достаточно больших размеров, то не будет ли проблем с доступом к ней во время бэкапа? Возможно стоит создавать копию базы на сервере Azure а потом уже бэкапить эту копию, а уж после бэкапа удалять копию.
P.S.
просто некоторые мысли в слух.
Насколько я знаю, экспорт базы средствами DAC не лочит базу. К тому же, если база большая, то я не думаю, что создание бекапа и создание копии БД сильно уж будут отличаться по нагрузке на сервер.
Мной была найдена тулза от RedGate которая как раз-таки и бэкапит базу с Azure.
http://www.red-gate.com/products/dba/sql-azure-backup/
при этом создает делает это через создание копии.
У тулзы есть интерфейс коммандной строки. Т.к. все что нужно это простой batch скрипт, который будет выполняться по расписанию.
Эта тулза, кстати, больше не поддерживается, а решение от RedGate мигрировала в облако.
К тому же есть аналогичные сервисы, поддерживаемые Microsoft — http://sqldacexamples.codeplex.com
Иными словами — я немного изобрел велосипед, зато кому надо — может этот велосипед использовать в своем проекте, если не желает полагаться на сторонние сервисы.
Оу… Давно не заходил на ваш сайт (ушел в веб :)), но недавно вспомнил про Вас, зашел на csharp-vip.ru И о чудо — он преобразовался в glamcoder 🙂 Просто слов нет) Мне интересно почему такой выбор?)
Назовем это рестайлингом. Решил закрыть проект C# VIP и сделать на его месте просто свой собственный техничческий блог, где я буду делиться различными техническими и не очень статьями. Все видео из C# VIP стали бесплатными и перекочевали на YouTube. Найти ссылки на них можно вверху сайта в разделе Видео
Тогда — поздравляю!)
Спасибо. Рад, что вам нравится, заходите чаще 🙂