Pull to refresh
147.26
Rating
Microsoft
Microsoft — мировой лидер в области ПО и ИТ-услуг

Миграция БД на Windows Azure SQL VM. BLOB Storage + REST

Microsoft corporate blog Microsoft SQL Server *
Теперь, когда мы имеем созданную в Облаке с установленным на нее SQL Server и умеем со стороны клиента с ним соединяться, как с локальным SQL Server, остается наполнить его данными. Предположим, в рамках гибридного сценария часть БД планируется перенести на Azure SQL VM. В этой статье будет рассматриваться сценарий, когда БД обособляется в виде файла (или нескольких файлов) посредством создания ее резервной копии, detach, data-tier application и т.д., файл доставляется на Azure SQL VM и превращается обратно в базу путем восстановления из бэкапа, attach, deploy/import data-tier application и т.д. Первое и последнее действие не вызывают вопросов у DBA. Осталось понять, как лучше доставить отчужденный файл с базой (.bak, .mdf, .bacpac, …) на облачную виртуалку с SQL Server.

Для примера перенесем любимую базу данных AdventureWorks в виде ее резервной копии:

backup database AdventureWorks2012 to disk = 'c:\Temp\AdventureWorks2012.bak' with init, compression, stats = 10
Скрипт 1

Файлы небольших размеров, как этот, можно, не мудрствуя лукаво, переносить обычным Copy/Paste на удаленный рабочий стол виртуальной машины SQL Server. Еще в голову приходит сделать на виртуалке папку общего доступа и скопировать туда, используя продвинутые средства копирования с возможностью распараллеливания, коррекции и взобновления в случае сбоев, а также передать файл по FTP. Эти способы очевидны. В данном посте мы задействуем иной способ: передадим файл бэкапа с локальной машины в Azure Storage в виде блоба и скачаем его оттуда внутрь облачной виртуалки. У нас уже имеется один Storage Account, созданный автоматически при создании виртуальной машины, в котором был автоматически контейнер по имени vhds, в котором в виде блоба хранится виртуальный диск нашей виртуальной машины. Для чистоты эксперимента создадим новый Storage Account под названием tststorage в том же центре обработки данных, что и облачная виртуалка, для сокращения накладных расходов.
Внутри Azure Storage данные могут храниться в виде блобов или таблиц — см. Azure Data Management and Business Analytics в документации Windows Azure. Таблицы не являются таблицами в строгом реляционном понимании. Это просто слабо структурированные наборы пар ключ-значение подобно тому, что когда-то называлось SQL Data Services — см. Введение в SQL Azure. По сравнению с SDS нынешние таблицы могут партиционироваться по ключу. Разные партиции хранятся на разных машинах в Облаке, чем достигается горизонтальное масштабирование, как при шардинге в случае SQL Azure Database. Блобы бывают блочные и страничные. Структура блочных блобов оптимизирована для подокового доступа, страничных – для случайного чтения/записи. Страничная структура позволяет запсать в блоб диапазон байтов. Подробно разница между ними объясняется, например, здесь — blogs.msdn.com/b/windowsazurestorage/archive/2010/04/11/using-windows-azure-page-blobs-and-how-to-efficiently-upload-and-download-page-blobs.aspx. Виртуальные диски хранятся как страничные блобы. Хранение блобов осуществляется внутри контейнеров, которые создаются в рамках Storage Account. Создадим в эккаунте tststorage контейнер container1 под хранение AdventureWorks2012.bak.
Публичный контейнер позволяет видеть любому желающему содержащиеся в нем блобы. Публичный блоб позволяет любому желающему доступаться к любому блобу, но содержание контейнера недоступно. Наконец, частный контейнер означает, что для доступа к блобу потребуется указывать ключ Storage Account. Изменить впоследствии уровень доступа к контейнеру можно при помощи кнопки Edit Container.
Сделанную в Скрипте 1 резервную копию базы для простоты будем загружать в Azure Storage как блочный блоб. Для операций над блобами в Облаке (равно как и над таблицами, и очередями) можно использовать REST, что позволяет работать напрямую через Интернет (HTTP Request/Response), привлекая широкий диапазон средств разработки. REST API для работы с блобами описывается здесь — msdn.microsoft.com/en-us/library/dd135733.aspx. Так можно посмотреть, какие блобы лежат в публичном контейнере: tststorage.blob.core.windows.net/container1?restype=container&comp=list
Контейнер container1 сейчас пуст. Чтобы загрузить в него AdventureWorks2012.bak, нужно использовать метод PUT:

using System;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Globalization;

class Program
{
static void Main(string[] args)
{
string fileFullName = @«c:\Temp\AdventureWorks2012.bak»; //@«c:\Temp\aaa.txt»;

string storageAccount = «tststorage»;
string containerName = «container1»;
string accessKey = «xws7rilyLjqdw8t75EHZbsIjbtwYDvpZw790lda0L1PgzEqKHxGNIDdCdQlPEvW5LdGWK/qOZFTs5xE4P93A5A==»;

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(String.Format(«https://{0}.blob.core.windows.net/{1}/{2}», storageAccount, containerName, Path.GetFileName(fileFullName)));

FileStream fs = File.OpenRead(fileFullName);
byte[] fileContent = new byte[fs.Length];
fs.Read(fileContent, 0, fileContent.Length);
fs.Close();

req.Method = «PUT»;
req.ContentLength = fileContent.Length;
req.Headers.Add(«x-ms-blob-type», «BlockBlob»);
req.Headers.Add(«x-ms-date», DateTime.UtcNow.ToString(«R», CultureInfo.InvariantCulture));
req.Headers.Add(«x-ms-version», «2011-08-18»);
string canonicalizedString = BuildCanonicalizedString(req, String.Format("/{0}/{1}/{2}", storageAccount, containerName, Path.GetFileName(fileFullName)));
req.Headers[«Authorization»] = CreateAuthorizationHeader(canonicalizedString, storageAccount, accessKey);
req.Timeout = 100 * 60 * 1000;
Stream s = req.GetRequestStream();
s.Write(fileContent, 0, fileContent.Length);

DateTime dt = DateTime.Now;
req.GetResponse();
System.Diagnostics.Debug.WriteLine(DateTime.Now — dt);

}

static string CreateAuthorizationHeader(string canonicalizedString, string storageAccount, string accessKey)
{
HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(accessKey));
byte[] dataToHMAC = Encoding.UTF8.GetBytes(canonicalizedString);
string signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHMAC));
return «SharedKey » + storageAccount + ":" + signature;
}

static string BuildCanonicalizedString(HttpWebRequest req, string canonicalizedResource)
{
StringBuilder sb = new StringBuilder();
sb.Append(req.Method + "\n\n\n");
sb.Append(String.Format("{0}\n\n\n\n\n\n\n\n\n", req.ContentLength));
sb.Append(«x-ms-blob-type:» + req.Headers[«x-ms-blob-type»] + '\n');
sb.Append(«x-ms-date:» + req.Headers[«x-ms-date»] + '\n');
sb.Append(«x-ms-version:» + req.Headers[«x-ms-version»] + '\n');
sb.Append(canonicalizedResource);
return sb.ToString();
}
}
Скрипт 2

В этом коде все достаточно очевидно за исключением, пожалуй, одного момента. Несмотря на то, что контейнер container1 был создан как публичный, запись блоба требует авторизации. Кто и какие операции может выполнять над блобами и контейнерами в зависимости от установленного уровня доступа описывается здесь — msdn.microsoft.com/en-us/library/dd179354.aspx. Вне зависимости от уровня доступа право на запись имеет владелец. Чтобы авторизоваться как владелец в HTTP Request требуется установить заголовок Authorization. Строка, записываемая в этот заголовок, в соответствии с требованиями схем аутентификации содержит подпись, которая представляет собой Hash-based Message Authentication Code (HMAC) канонизированной строки в кодировке UTF-8, где хэш вычисляется по алгоритму SHA256 на основе ключа доступа. Канонизированная строка складывается из метода доступа REST, размера загружаемого файла, типа блоба (x-ms-blob-type = блочный или страничный) даты/времени HTTP-запроса в формате UTC (x-ms-date), даты версии блобовского сервиса Azure, обслуживающего данный HTTP-запрос (x-ms-version) и др. Здесь не требуется блистать высоким программерским искусством, нужна лишь кропотливость и внимательность, т.к. малейшая неаккуратность при формировании канонизированной строки неумолимо влечет ошибку HTTP 403 Forbidden.
Ключи доступа (основной и запасной) формируются на этапе создания Storage Account, их можно посмотреть в свойствах контейнера (Manage Keys). Любой из них можно задавать в качестве accessKey для создания цифровой подписи при авторизации — HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(accessKey));
Для более гранулярнного управления правами можно использовать подпись общего доступа (Shared Access Signature). Подпись общего доступа позволяет создать политику, позволяющую выполнять определенную операцию, например, запись внутри определенного контейнера в пределах отведенного промежутка времени. Человек, которому вручается подпись, будет способен действовать в рамках этой политики. Другая подпись, например, может уполномачивать читать из другого контейнера в течение другого периода.
Прочие комментарии.
• Если блоб с таким именем в контейнере существует, он молчаливо перетирается.
• Имя контейнера чувствительно к регистру.
• Время загрузки, очевидно, зависит от скорости сетки. Например, с работы данный 45-меговый бэкап залился со свистом за 00:01:07. Из дома получалось в разы медленнее.
В данном демонстрационном примере бэкап имел достаточно «детский» размер. Блочные блобы ограничены размером в 200 ГБ. Блочный блоб размером менее 64 МБ может быть загружен одной операцией записи, как мы наблюдали в примере Скрипт 2. В противном случае следует разбивать его на куски и загружать поблочно с использованием методов Put Block / Put Block List. При заливке в Azure Storage крупных файлов следует применять страничные блобы. Страничный блоб состоит из 512-байтных страниц, его максимальный размер составляет 1 ТБ. Пример на запись/чтение диапазона страниц страничного блоба приводится здесь — blogs.msdn.com/b/windowsazurestorage/archive/2010/04/11/using-windows-azure-page-blobs-and-how-to-efficiently-upload-and-download-page-blobs.aspx.
Tags:
Hubs:
Total votes 17: ↑9 and ↓8 +1
Views 1.8K
Comments Leave a comment

Information

Founded
Location
США
Website
www.microsoft.com
Employees
Unknown
Registered