Стоимость хранения данных на дисках упала настолько кардинально, что кажется просто фантастикой, и это открывает компаниям все возможности хранения огромных объемов данных. Но возможность хранить массу данных, с экономической точки зрения, решает лишь половину проблемы. Наборы данных становятся настолько велики и сложны, что традиционные средства управления базами данных и приложения для обработки данных оказываются неадекватными. С такими объемами данных на дисках возникают новые проблемы, например организация данных, их поиск, совместное использование, анализ и в конечном счете визуализация.
И мощь облачных вычислений удовлетворяет эти потребности. Возможности выполнения программных решений с высокой степенью распараллеливания на десятках, сотнях или даже тысячах серверов — верное решение проблемы, позволяющее организациям иметь дело с любыми объемами накопленных данных.
Microsoft осознала эту важную тенденцию еще несколько лет назад. Windows Azure Storage (WAS) была выпущена в ноябре 2008 года и кардинально расширила возможности организаций в извлечении выгоды из массивов хранимых данных.
По словам Брэда Калдера (Brad Calder), заслуженного инженера Microsoft и руководителя разработчиков системы WAS, «Windows Azure Storage — это облачная система хранения, которая дает возможность потребителям хранить практически безграничные объемы данных в течение любого времени и при этом обеспечивает их высокую доступность и надежность. В случае Windows Azure Storage вы получаете доступ к своим данным откуда угодно, в любое время и платите лишь за то, что используете и храните».
WAS используется в Microsoft в таких областях, как поиск по социальным сетям, обслуживание видео-, музыкального и игрового контента, а также для управления медицинскими документами. Она также применяется поисковой системой Bing для почти мгновенного предоставления открытого для поиска контента из публикаций в Facebook или Twitter и обновлений статусов. Объем данных Facebook и Twitter составляют почти 350 Тб. При использовании этих данных требуется до 40 000 транзакций в секунду и около 2–3 миллиардов транзакций ежедневно.
В этой статье мы исследуем одну из граней WAS — Windows Azure Tables; мы рассмотрим, как она устроена и как разработчики могут быстро приступить к работе с ней.
Введение
В наше время выбор платформ данных весьма широк, и каждая из них имеет свои сильные и слабые стороны. Например, многие решения в области работы с огромными массивами данных базируются на концепции NoSQL, подразумевающей отказ от модели управления реляционными базами данных — никаких таблиц и никаких SQL-выражений. Вместо этого структуры данных, как правило, являются массивными наборами пар «ключ-значение» или ассоциативными массивами. Сегодня наибольшей популярностью пользуются Mon-goDB, Cassandra, HBase, CouchDB, Neo4j и Windows Azure Tables. Эта статья посвящена Windows Azure Ta-bles.
Несмотря на существенные различия, у баз данных SQL и NoSQL есть одно общее свойство: эти технологии предлагаются как сервис в облаке, освобождая разработчиков от необходимости ручной подготовки серверов данных. Так, Windows Azure Tables предоставляется как сервис, и разработчику никогда не придется мыслить в терминах раздельных физических серверов.
Сегодня мы начнем с краткого обсуждения некоторых функций и возможностей Windows Azure Tables. Затем мы представим кое-какой код, демонстрирующий, как можно работать с Windows Azure Tables в терминах вставки и запроса данных. И наконец, мы рассмотрим некоторые цели проектирования и детали высокоуровневой реализации WAS.
Некоторые основы
Одна из важных особенностей Windows Azure Tables заключается в том, что это хранилище географически распределено по трем регионам: США, Европе и Азии. Каждый информационный центр Microsoft соответствует ISO-стандарту 27001 (International Organization for Standardization), а также стандартам SSAE 16 ISAE 3402, EU Model Clauses и Health Insurance Portability and Accountability Act (HIPAA) Business Associate Agreement (BAA). Другая важная особенность — хранилище с избыточным территориальным распределением (geo-redundant storage), что позволяет вам реплицировать свои данные в другой информационный центр в пределах того же региона, тем самым добавляя еще один уровень восстановления на случай каких-либо катастроф.
Производительность и пространства для хранения в WAS коррелируют с учетными записями хранилища. Индивидуальная учетная запись включает до 200 Тб. Windows Azure Tables оптимизирована для обеспечения невероятно быстрого выполнения запросов под высокими нагрузками, связанными с записью в хранилище. Подробнее об этом см. по ссылке bit.ly/cMAWsZ.
В табл. 1 показаны показатели масштабируемости для одной учетной записи, созданной после 7 июня 2012 г.
Табл. 1. Показатели масштабируемости для одной учетной записи
Индивидуальные учетные записи хранилища |
Емкость | Вплоть до 200 Тб |
Транзакции | Вплоть до 20 000 сущностей/сообщений/объектов в секунду |
Полоса пропускания для учетной записи с избыточным территориальным распределением |
Вход | Вплоть до 5 Гбит/с |
Выход | Вплоть до 10 Гбит/с |
Полоса пропускания для учетной записи с избыточным локальным распределением |
Вход | Вплоть до 10 Гбит/с |
Выход | Вплоть до 15 Гбит/с |
Также доступны аналитические средства WAS, которые позволяют разработчикам отслеживать запросы к хранилищу, анализировать тенденции использования и оптимизировать шаблоны доступа к данным в учетной записи хранилища. Подробнее об этом см. по ссылке bit.ly/XGLtGt.
Вы должны знать, что система WAS включает и другие абстракции, такие как большие двоичные объекты (blobs), или просто объекты, и очереди. Мы сосредоточимся здесь на Windows Azure Tables, которая применяется для хранения нереляционных структурированных и полуструктурированных данных. Если быть предельно лаконичным, то ценность Windows Azure Tables заключается в том, что она поддерживает NoSQL-поиск по ключу и/или значению с масштабированием и в условиях высокой нагрузки по записи. С точки зрения разработчика, Windows Azure Tables предназначена для хранения больших наборов разнородных объектов или для обслуживания страниц на веб-сайте с интенсивным трафиком.
К Windows Azure Tables можно обращаться практически откуда угодно. Вся эта система хранения поддерживает Representational State Transfer (REST), а значит, любой клиент, поддерживающий HTTP, может взаимодействовать с системой WAS. Очевидно, что к таким клиентам относятся iOS, Android, Windows 8 и различные дистрибутивы Linux. REST API поддерживает операции вставки, обновления и вставки (upserts), обновления и удаления, выбора и запросов.
Главное при начале работы с Windows Azure Tables — понимать, как управлять схемой разбиения данных на разделы (data partitioning). Для каждой таблицы Windows Azure архитектор данных должен заранее определить PartitionKey и RowKey. По-видимому, это самое важное решение, принимаемое при использовании Windows Azure Tables. Значения PartionKey и RowKey определяют, как ваши данные автоматически разбиваются на разделы сервисом хранилища и каким образом будут выполняться ваши запросы. Рекомендуется, чтобы вы понимали, как будут запрашиваться ваши данные до окончательных решений по PartitionKey и RowKey. Потом мы углубимся в механику транзакционной согласованности и ее взаимосвязь с ключами PartitionKey. А пока пройдем простой пример того, как система WAS разбивает на разделы табличные данные.
Быстрое обучение
Вообразите, что вы хотите хранить и получать сообщения электронной почты из различных доменов, например bterkaly@microsoft.com, ricardo.villalobos@microsoft.com, brunoterkaly@hotmail.com и ricardovilla-lobos@hotmail.com. В этих адресах электронной почты именами доменов являются microsoft.com и hot-mail.com, а именами электронной почты — bterkaly и ricardo.villalobos. В типичных запросах сначала осуществляется поиск по имени домена, а затем по имени электронной почты.
В этом простом примере выбор PartitionKey и RowKey достаточно прямолинеен. Мы сопоставим имя домена с PartitionKey, а имя электронной почты — с RowKey.
Код на рис. 1 должен немного прояснить все это. Он демонстрирует четыре простые возможности:
- определение сущности (EmailAddressEntity);
- определение таблицы, которая будет хранить сущности (EmailAddressTable);
- вставку сущности в таблицу (вставку EmailAddressEntity в EmailAddressTable);
- запрос таблицы для поиска конкретной сущности (поиск bterkaly@microsoft.com).
Рис. 1. Сущность EmailAddressEntity
// Наша сущность наследует от TableEntity
public class EmailAddressEntity : TableEntity
{
// Базовая информация, составляющая нашу сущность
public string EMailAddress { get; set; }
public string PhoneNumber { get; set; }
// Обязательный конструктор по умолчанию
public EmailAddressEntity()
{
}
// Конструктор, принимающий два параметра
public EmailAddressEntity(string email, string phone)
{
EMailAddress = email;
PhoneNumber = phone;
SetKeys(email, phone);
}
// Метод, инициализирующий ключи раздела и строки
public void SetKeys(string email, string phone)
{
int startIndex = email.IndexOf("@");
// Извлекаем mailname из адреса электронной почты
string mailname = email.Substring(0, startIndex);
// Извлекаем domain из адреса электронной почты
string domain = email.Substring(startIndex + 1);
// Обязательные назначения ключам раздела и строки
PartitionKey = domain;
RowKey = mailname;
PhoneNumber = phone;
}
}
Сначала мы определяем структуру самой сущности EmailAddressEntity, как показано на рис. 1. Реальная таблица (контейнер сущностей) будет определена позже, когда мы вставим EmailAddressEntity в таблицу. Сущность можно рассматривать как индивидуальный объект; это самая малая единица данных, которую можно хранить в Windows Azure Table. Как упоминалось ранее, сущность — это набор типизированных пар «имя-значение», которые зачастую называют свойствами. Таблицы представляют собой наборы сущностей, и каждая сущность принадлежит таблице точно так же, как строка в таблице реляционной базы данных. Но таблицы в Windows Azure Table Storage не имеют фиксированной схемы. Никаких требований к тому, чтобы все сущности в таблице были структурно идентичными, как в случае таблицы реляционной базы данных, нет.
На рис. 1 видны четыре основные части информации. Первые две, EMailAddress и PhoneNumber, — просто две строки, которые мы хотим хранить. Остальные две — это свойства PartitionKey и RowKey, рассмотренные ранее. Третье свойство, обязательное для всех сущностей, — Timestamp; оно используется системой на внутреннем уровне и способствует параллельному доступу с нежесткой блокировкой (optimistic concurrency).
Поле Timestamp отличается от полей PartitionKey и RowKey, так как оно заполняется автоматически системой WAS. В противоположность ему свойства PartitionKey и RowKey должны вставляться разработчиками.
Резюмируя, отметим, что важность PartitionKey и RowKey в основном связана с производительностью запросов и транзакционной согласованностью. Мы уже давали пояснения по производительности запросов, и она в большей мере зависит от того, как данные распределяются по узлам хранилища. Но PartitionKey также позволяют вносить изменения во множество сущностей в рамках одной операции, что дает возможность разработчикам откатывать изменения в случае неудачи любой одной операции. Требование в том, что сущности должны быть частью одной группы сущностей, что на деле означает, что сущности используют один и тот же PartitionKey. Транзакции поддерживаются в рамках одного PartitionKey.
Код на рис. 2 иллюстрирует создание экземпляра сущности типа EmailAddressEntity (с рис. 1) и последующую вставку этой сущности в EmailAddressTable. Заметьте, что мы используем эмулятор локального хранилища. Это позволяет нам выполнять и тестировать наш код и данные локально, без подключения к информационному центру.
Рис. 2. Вставка EmailAddressEntity
try
{
// Используем эмулятор локального хранилища
var storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
// Создаем клиентский объект облачной таблицы
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
// Создаем объект таблицы адресов электронной почты
CloudTable emailAddressTable =
tableClient.GetTableReference("EmailAddressTable");
// Создаем таблицу, если ее еще нет. Вставляем
// одну новую запись только для данной демонстрации.
if (emailAddressTable.CreateIfNotExists() == true)
{
// Создаем новую сущность EmailAddressEntity
EmailAddressEntity emailaddress = new EmailAddressEntity(
"bterkaly@microsoft.com", "555-555-5555");
// Создаем операцию для добавления нового адреса
// электронной почты и телефонного номера
// в emailAddressTable
TableOperation insertEmail = TableOperation.Insert(emailaddress);
// Передаем эту операцию сервису таблиц
emailAddressTable.Execute(insertEmail);
}
}
catch (Exception ex)
{
// Помещаем сообщение в заголовок веб-страницы (для теста).
// На практике сообщения об ошибках должны записываться
// в подходящий файл журнала
this.Title = ex.Message.ToString();
throw;
}
Вы можете просматривать свои данные в Server Explorer в Visual Studio 2012, как показано на рис. 3; это значительно упрощает процесс написания и тестирования кода. Вы также можете присоединить Server Explorer к реальному экземпляру своего хранилища Windows Azure Tables в информационном центре.
Рис. 3. Server Explorer
Код на рис. 4 иллюстрирует, как запрашивать данные.
Рис. 4. Запрос Windows Azure Tables
// Используем эмулятор локального хранилища
var storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
try
{
// Создаем клиент таблицы
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable emailAddressTable =
tableClient.GetTableReference("EmailAddressTable");
// Получаем сущность с ключом раздела "microsoft.com"
// и ключом строки "bterkaly"
TableOperation retrieveBrunoEmail =
TableOperation.Retrieve<EmailAddressEntity>(
"microsoft.com", "bterkaly");
// Получаем сущность
EmailAddressEntity specificEntity =
(EmailAddressEntity)emailAddressTable.Execute(retrieveBrunoEmail).Result;
TableResult result =
emailAddressTable.Execute(TableOperation.Retrieve<EmailAddressEntity>(
"microsoft.com", "bterkaly"));
// Извлекаем искомые данные. Что-то делаем
// с emailAddress и phoneNumber.
string emailAddress = specificEntity.EMailAddress;
string phoneNumber = specificEntity.PhoneNumber;
}
catch (Exception ex)
{
// Помещаем сообщение в заголовок веб-страницы (для теста).
// На практике сообщения об ошибках должны записываться
// в подходящий файл журнала
this.Title = ex.Message.ToString();
throw;
}
Этот код выполняет простой запрос, используя PartitionKey и RowKey. Заметьте, что вы можете конструировать довольно сложные запросы, применяя эти фильтры, так как их можно комбинировать. Мы сформировали объект запроса с использованием комбинированного фильтра. Финальный этап — выполнение запроса и любые необходимые операции с EmailAddressEntity. WAS Client Library значительно упрощает как CRUD-операции (Create/Read/Update/Delete), так и необходимые запросы.
Что внутри
Мы сочли полезным поглубже рассмотреть внутреннюю архитектуру системы WAS (рис. 5). Многое из того, что будет говориться далее, основано на статье Брэда Калдера, ссылка на которую приводится далее в этой статье.
Рис. 5. Внутреннее устройство Windows Azure Storage
Data Access | Доступ к данным |
Storage Location Service | Storage Location Service |
LB | LB |
Front Ends | Клиентские интерфейсы |
Partition Layer | Уровень раздела |
Geo-Replication | Территориальная репликация |
Stream Layer | Уровень потока данных |
Intra-Stamp Replication | Репликация с внутренними метками |
Storage Stamp | Метка хранилища |
WAS состоит из серии меток хранилищ, распределенных по восьми информационным центрам. Метка хранилища (storage stamp) — это кластер, содержащий примерно от 10 до 20 стоек (racks) узлов хранилища. Каждая стойка находится в отдельном домене сбоя (fault domain). Каждая стойка снабжается избыточными сетевыми подключениями и электропитанием. Каждая метка хранилища содержит приблизительно 30 Пб исходного пространства хранения.
Для поддержания низких затрат важно использовать эти метки не менее чем на 70% в терминах емкости, транзакций и полосы пропускания. Однако нагрузка более 90% считается слишком высокой, так как при этом остается слишком мало места для маневра на случай сбоев серверных стоек, когда системе приходится делать больше меньшими средствами.
Storage Location Service
У разработчика нет прямого контроля над Storage Location Service (SLS). На уровне учетной записи SLS не только сопоставляет пространства имен учетной записи между всеми метками, но и отвечает за восстановление после катастроф, создание учетных записей хранилищ и балансировку нагрузки. SLS сильно упрощает добавление нового хранилища в информационном центре. Она может создавать новые учетные записи хранилища в новых метках для потребителей, а также выполнять балансировку нагрузки по существующим учетным записям хранилищ, используя более старые метки для новых меток. Все эти операции SLS выполняет автоматически.
Давайте немного подробнее рассмотрим три уровня, образующих метку хранилища: поток данных (stream), раздел (partition) и клиентский интерфейс (front end, FE). И начнем снизу вверх.
Уровень потока данных предоставляет внутренний интерфейс, используемый уровнем раздела для чтения и записи больших файлов, а также отвечает за базовую функциональность репликации. Кроме того, уровень потока данных обрабатывает открытие, закрытие, удаление, переименование, чтение, конкатенацию этих больших файлов и дозапись в них. При этом он не имеет дела с семантикой объектов, находящихся в потоке данных.
Windows Azure Storage Client Library 2.0
В конце октября 2012 года Microsoft выпустила новую клиентскую библиотеку хранилища — Win-dows Azure Storage (WAS) Client Library 2.0, которая кардинально улучшила удобство использования, расширяемость и производительность при взаимодействии с Windows Azure Tables. Вы можете установить WAS Client Library 2.0 с помощью NuGet по ссылке bit.ly/YFeHuw. Это можно сделать в Visual Studio 2012. Детальное описание некоторых новых замечательных функций в этой библиотеке см. по ссылке bit.ly/VQSaUv.
Новая библиотека включает некоторые новые подходы, которые улучшают функциональность в отношении удобства в использовании, расширения и производительности. Одна из замечательных функций избавляет вас от возни с логикой сериализации и десериализации при работе с Plain Old C# Objects (POCO). Другая замечательная функция — EntityResolver, которая позволяет выполнять проекции на клиентской стороне, благодаря чему вы можете создавать объекты «на лету», основываясь лишь на интересующей вас информации. Если кратко, то вы можете напрямую преобразовывать данные табличной сущности в клиентский тип объекта без отдельного класса табличной сущности, который обеспечивает индивидуальную десериализацию каждого свойства. Еще одна замечательная технология — интерфейс IQueryable, который дает способ выразительного определения сложных LINQ-запросов.
Уровень раздела предоставляет модель данных для различных типов хранимых объектов (таблиц, больших двоичных объектов, очередей), логику и семантику для обработки различных типов объектов, масштабируемое пространство имен для объектов, балансировку нагрузки для доступа к объектам между доступными серверами раздела, упорядочение транзакций и строгую согласованность для доступа к объектам, а также репликацию объектов данных из основного региона в дополнительный.
Этот уровень также инкапсулирует важную внутреннюю структуру данных — Object Table. Существует несколько версий Object Table, в том числе Entity Table, которая хранит все строки сущностей для всех учетных записей в метке. Она используется для того, чтобы сделать абстракцию данных Windows Azure Table общедоступной. Object Table также взаимодействует с уровнем раздела для обеспечения целостности данных за счет упорядочения транзакций с большими двоичными объектами, таблицами и очередями.
Уровень FE состоит из набора не поддерживающих состояние серверов, которые принимают входящие запросы. При получении запроса FE находит AccountName, аутентифицирует и авторизует запрос, а затем направляет его соответствующему серверу в уровне раздела (на основе PartitionName). Для большей производительности FE поддерживает и кеширует Partition Map, чтобы ускорить маршрутизацию запроса соответствующему серверу раздела с учетом часто используемых данных.
Заключение
В этой статье мы дали некоторые высокоуровневые, требующие внимания правила, а также описали ряд архитектурных деталей, относящихся ко внутреннему устройству системы WAS, и, в частности, рассказали, как Windows Azure Tables может помочь в управлении вашими данными. Мы хотели бы поблагодарить Брэда Калдера за некоторую уникальную информацию, которой он поделился в недавней статье «Windows Azure Storage: A Highly Available Cloud Storage Service with Strong Consistency», опубликованной на 23-м симпозиуме ACM Symposium on Operating Systems Principles (SOSP). Вы можете скачать его статью по ссылке bit.ly/tMIPus.