Блог Георгия Могелашвили

Сервис автоматизированных бекапов Windows Azure SQL database в хранилище Blob Storage

Сервис автоматизированных бекапов Windows Azure SQL database в хранилище Blob Storage

blob storage

Привет. Некоторое время назад в официальной русской группе 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.”. Может у кого-то из читателей найдется ответ, как лучше все это провернуть. Ну или успокоит меня, что временные файлы – вполне себе гуд.

8 комментариве к “Сервис автоматизированных бекапов Windows Azure SQL database в хранилище Blob Storage

  1. Disposer

    Если это продакшен база, достаточно больших размеров, то не будет ли проблем с доступом к ней во время бэкапа? Возможно стоит создавать копию базы на сервере Azure а потом уже бэкапить эту копию, а уж после бэкапа удалять копию.

    P.S.
    просто некоторые мысли в слух.

    1. Георгий Могелашвили Автор записи

      Насколько я знаю, экспорт базы средствами DAC не лочит базу. К тому же, если база большая, то я не думаю, что создание бекапа и создание копии БД сильно уж будут отличаться по нагрузке на сервер.

  2. Disposer

    Мной была найдена тулза от RedGate которая как раз-таки и бэкапит базу с Azure.
    http://www.red-gate.com/products/dba/sql-azure-backup/
    при этом создает делает это через создание копии.

    У тулзы есть интерфейс коммандной строки. Т.к. все что нужно это простой batch скрипт, который будет выполняться по расписанию.

    1. Георгий Могелашвили Автор записи

      Эта тулза, кстати, больше не поддерживается, а решение от RedGate мигрировала в облако.
      К тому же есть аналогичные сервисы, поддерживаемые Microsoft – http://sqldacexamples.codeplex.com
      Иными словами – я немного изобрел велосипед, зато кому надо – может этот велосипед использовать в своем проекте, если не желает полагаться на сторонние сервисы.

  3. Глеб

    Оу… Давно не заходил на ваш сайт (ушел в веб :)), но недавно вспомнил про Вас, зашел на csharp-vip.ru И о чудо – он преобразовался в glamcoder 🙂 Просто слов нет) Мне интересно почему такой выбор?)

    1. Георгий Могелашвили Автор записи

      Назовем это рестайлингом. Решил закрыть проект C# VIP и сделать на его месте просто свой собственный техничческий блог, где я буду делиться различными техническими и не очень статьями. Все видео из C# VIP стали бесплатными и перекочевали на YouTube. Найти ссылки на них можно вверху сайта в разделе Видео

Добавить комментарий

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