Добрый день. Мы продолжаем с вами знакомиться с технологиями хранения данных в Windows Azure. Сегодня поговорим о таблицах и очередях. Что это такое и с чем его едят.
Очередь.
И начнем мы с очередей. Если давать определение очереди с точки зрения программиста, то это механизм хранения данных работающий по принципу FIFO (First In First Out). Да, это довольно таки старый паттерн, но он нашел свое применение в облаке. Нашел, но несколько в ином обличии. Во-первых используя Windows Azure Queues мы не можем быть уверенными, что сообщения будут поступать и изыматься из очереди по ее основному принципу FIFO, то есть порядок не гарантируется. Именно из-за этого ограничения
облачная очередь служит для несколько иных целей, а именно для организации асинхронной системы. То есть Windows Azure Queues служит своеобразным коммуникационным каналом между различными частями одного и того же приложения, либо между совершенно разными приложениями. Например, хорошим примером может быть сценарий размещения изображений на вашем сервере, в котором пользователи могут отправлять новые изображения посредством Веб-роли, а ваша фоновая worker-роль будет создавать для них уменьшенные копии. При таком сценарии имеет смысл отправлять новые работы по созданию изображений различных масштабов фоновому процессу посредством Windows Azure Queue. Давайте ближе познакомимся с очередью. Логическая организация очереди представлена на рисунке ниже:
Как мы видим, на верхнем уровне иерархии находится аккаунт, аккаунт может содержать неограниченное количество очередей, каждая из которых способна хранить неограниченное количество сообщений. Список операций, которые мы можем выполнять над очередью также довольно таки стандартный:
Следующая нереляционная технология, о которой я хотел бы рассказать – это хранение данных при помощи таблиц или Windows Azure Table Storage.
Таблицы.
Согласно определению, таблицы представляют собой хранилища данных, в которых эти данные организованы в сущности, а сущности в свою очередь состоят из свойств. Схематически это будет выглядеть так:
На верхнем уровне иерархии без изменений – это опять же наш аккаунт. Каждый аккаунт может включать в себя неограниченное количество таблиц. Таблица содержит множество сущностей (можно провести аналогию со строкой в таблице реляционной базы данных) каждая из которых может содержать множество свойств (по аналогии с колонкой в таблице реляционной базы данных). Как мы видим концептуально некая схожесть с реляционными таблицами присутствует, но не более. Во-первых Windows Azure Tables совершенно независимы от схемы в отличии от реляционных таблиц, это означает, что в контексте одной таблицы могут присутствовать объекты с совершенно разным набором полей-свойств. Во-вторых нет никакой ссылочной целостности, то есть джойны здесь не работают. Из других особенностей следует отметить следующие:
Пример взаимодействия с очередью и хранилищем блобов.
На этом я хотел бы закончить с теорией и продемонстрировать фрагменты кода по взаимодействию с хранилищем блобов и очередью. Приложение содержит в себе 2 роли – это web-роль и worker-роль.
Пользователи взаимодействуют с веб-ролью и имеют возможность загружать изображения в хранилище блобов. В свою очередь при каждой загрузке нового изображения веб-роль посылает сообщение worker-роли о наличии нового изображения. Увидев это, worker-роль автоматически создает для изображения его уменьшенную версию и сохраняет ее все в том же хранилище блобов. Коммуникация между ролями осуществляется при помощи очереди. Процесс сохранения загруженного изображения в хранилище блобов представлен чуть ниже:
Фоновая программа, наша worker-роль постоянно прослушивает очередь на предмет поступления новых данных. Как только данное событие наступает запускается механизм создания уменьшенной копии изображения и сохранения ее в подкаталог thumbnails хранилища блобов. Код выполняющий данные действия представлен ниже:
На этом я хотел бы закончить часть посвященную нереляционным хранилищам данных в Windows Azure. В последующих публикациях я поведаю Вам об альтернативном реляционном варианте хранения данных в облаке под названием SQLAzure. Спасибо за внимание !
Очередь.
И начнем мы с очередей. Если давать определение очереди с точки зрения программиста, то это механизм хранения данных работающий по принципу FIFO (First In First Out). Да, это довольно таки старый паттерн, но он нашел свое применение в облаке. Нашел, но несколько в ином обличии. Во-первых используя Windows Azure Queues мы не можем быть уверенными, что сообщения будут поступать и изыматься из очереди по ее основному принципу FIFO, то есть порядок не гарантируется. Именно из-за этого ограничения
облачная очередь служит для несколько иных целей, а именно для организации асинхронной системы. То есть Windows Azure Queues служит своеобразным коммуникационным каналом между различными частями одного и того же приложения, либо между совершенно разными приложениями. Например, хорошим примером может быть сценарий размещения изображений на вашем сервере, в котором пользователи могут отправлять новые изображения посредством Веб-роли, а ваша фоновая worker-роль будет создавать для них уменьшенные копии. При таком сценарии имеет смысл отправлять новые работы по созданию изображений различных масштабов фоновому процессу посредством Windows Azure Queue. Давайте ближе познакомимся с очередью. Логическая организация очереди представлена на рисунке ниже:
Как мы видим, на верхнем уровне иерархии находится аккаунт, аккаунт может содержать неограниченное количество очередей, каждая из которых способна хранить неограниченное количество сообщений. Список операций, которые мы можем выполнять над очередью также довольно таки стандартный:
- Получение списка очередей, привязанных к аккаунту
- Создание/удаление очереди
- Получение/установка метаданных очереди
- Очистка очереди
- Добавление/получение/удаление сообщений
Следующая нереляционная технология, о которой я хотел бы рассказать – это хранение данных при помощи таблиц или Windows Azure Table Storage.
Таблицы.
Согласно определению, таблицы представляют собой хранилища данных, в которых эти данные организованы в сущности, а сущности в свою очередь состоят из свойств. Схематически это будет выглядеть так:
На верхнем уровне иерархии без изменений – это опять же наш аккаунт. Каждый аккаунт может включать в себя неограниченное количество таблиц. Таблица содержит множество сущностей (можно провести аналогию со строкой в таблице реляционной базы данных) каждая из которых может содержать множество свойств (по аналогии с колонкой в таблице реляционной базы данных). Как мы видим концептуально некая схожесть с реляционными таблицами присутствует, но не более. Во-первых Windows Azure Tables совершенно независимы от схемы в отличии от реляционных таблиц, это означает, что в контексте одной таблицы могут присутствовать объекты с совершенно разным набором полей-свойств. Во-вторых нет никакой ссылочной целостности, то есть джойны здесь не работают. Из других особенностей следует отметить следующие:
- Сущность может иметь до 255 полей и ее размер не должен превышать 1 Мб
- Сущность идентифицируется набором идентификаторов секции и строки
- Поля могут быть стандартными .NET типами
Пример взаимодействия с очередью и хранилищем блобов.
На этом я хотел бы закончить с теорией и продемонстрировать фрагменты кода по взаимодействию с хранилищем блобов и очередью. Приложение содержит в себе 2 роли – это web-роль и worker-роль.
Пользователи взаимодействуют с веб-ролью и имеют возможность загружать изображения в хранилище блобов. В свою очередь при каждой загрузке нового изображения веб-роль посылает сообщение worker-роли о наличии нового изображения. Увидев это, worker-роль автоматически создает для изображения его уменьшенную версию и сохраняет ее все в том же хранилище блобов. Коммуникация между ролями осуществляется при помощи очереди. Процесс сохранения загруженного изображения в хранилище блобов представлен чуть ниже:
- // В первую очередь получаем ссылку на аккаунт, строку соединения берем из конфигурационного файла
- var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
- CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
- // Дальше получаем ссылку на целевой контейнер и создаем его если он не существует
- CloudBlobContainer container = blobClient.GetContainerReference("photogallery");
- container.CreateIfNotExist();
- // Устанавливаем уровни доступа к контейнеру, в данном случае у нас открытый контейнер
- var permissions = container.GetPermissions();
- permissions.PublicAccess = BlobContainerPublicAccessType.Container;
- container.SetPermissions(permissions);
- // Создаем клиент к сервису очередей
- CloudQueueClient queueStorage = storageAccount.CreateCloudQueueClient();
- // Получаем ссылку на интересующую нас очередь и создаем ее если она не существует
- CloudQueue queue = queueStorage.GetQueueReference("thumbnailmaker");
- queue.CreateIfNotExist();
- // Далее получаем ссылку на интересующий нас блоб, фукнция принимает имя блоба
- var targetBlob = container.GetBlockBlobReference("BlobImage.jpg");
- // и загружаем в него содержимое изображения
- targetBlob.UploadFromStream(inputFile.FileContent);
- // Последним действием отправляем сообщение в очередь с именем загруженного блоба для последующей обработки
- queue.AddMessage(new CloudQueueMessage(System.Text.Encoding.UTF8.GetBytes("BlobImage.jpg")));
- public class WorkerRole : RoleEntryPoint
- {
- private Stream CreateThumbnail(Stream input)
- {
- // Создаем уменьшенное изображение и возвращаем его виде потока вызывающему коду
- }
- public override bool OnStart()
- {
- // Код выполняющий инициализацию роли.
- }
- public override void Run()
- {
- CloudBlobClient blobStorage = null ;
- CloudBlobContainer blobContainer = null ;
- CloudQueueClient queueStorage = null ;
- CloudQueue queue = null ;
- // Получение ссылки на аккаунт
- var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
- bool containerAndQueueCreated = false;
- while (!containerAndQueueCreated)
- {
- try
- {
- // Инициалируем клиент. предназначенный для взаимодействия с хранилищем блобов
- blobStorage = storageAccount.CreateCloudBlobClient();
- // Получаем ссылку интересующий нас контейнер
- blobContainer = blobStorage.GetContainerReference("photogallery");
- // Создаем клиент для взаимодействия с очередью и получаем ссылку на конкретную очередь, которая будет содержать наши сообщения
- queueStorage = storageAccount.CreateCloudQueueClient();
- queue = queueStorage.GetQueueReference("thumbnailmaker");
- queue.CreateIfNotExist();
- containerAndQueueCreated = true;
- }
- catch (StorageClientException e)
- {
- if (e.ErrorCode == StorageErrorCode.TransportError)
- {
- Trace.TraceError(string.Format("Connect failure! The most likely reason is that the local " +
- "Development Storage tool is not running or your storage account configuration is incorrect. " +
- "Message: '{0}'", e.Message));
- System.Threading.Thread.Sleep(5000);
- }
- else
- {
- throw;
- }
- }
- }
- Trace.TraceInformation("Listening for queue messages...");
- // Входим в бесконечный цикл ожидания поступления новых данных
- while (true)
- {
- try
- {
- CloudQueueMessage msg = queue.GetMessage();
- // Если из очереди получили новое сообщение то приступаем к его обработке
- if (msg != null)
- {
- string path = msg.AsString;
- string thumbnailName = System.IO.Path.GetFileNameWithoutExtension(path) + ".jpg";
- Trace.TraceInformation(string.Format("Dequeued '{0}'", path));
- // Сообщение содержит имя блоба, получаем ссылку на этот блоб
- CloudBlockBlob content = blobContainer.GetBlockBlobReference(path);
- // и сохраняем уменьшенную версию с префиксом thumbnails/
- CloudBlockBlob thumbnail = blobContainer.GetBlockBlobReference("thumbnails/" + thumbnailName);
- thumbnail.Properties.ContentType = "image/jpeg";
- MemoryStream image = new MemoryStream();
- content.DownloadToStream(image);
- image.Seek(0, SeekOrigin.Begin);
- Stream tn = CreateThumbnail(image);
- thumbnail.UploadFromStream(tn);
- // Физически удаляем сообщение из очереди
- queue.DeleteMessage(msg);
- }
- // Если новых сообщение в очереди нет, то засыпаем на 5 секунд
- else
- {
- System.Threading.Thread.Sleep(5000);
- }
- }
- catch (Exception e)
- {
- // Explicitly catch all exceptions of type StorageException here because we should be able to
- // recover from these exceptions next time the queue message, which caused this exception,
- // becomes visible again.
- System.Threading.Thread.Sleep(5000);
- Trace.TraceError(string.Format("Exception when processing queue item. Message: '{0}'", e.Message));
- }
- }
- }
- }
Комментариев нет:
Отправить комментарий