ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 21.04.2024
Просмотров: 279
Скачиваний: 1
размещением сущностей в одной секции, что обеспечивает большую эффективность запросов, и масштабируемостью таблицы, поскольку, чем больше секций в таблице, тем проще для Windows Azure Table распределить нагрузку между множеством серверов.
Для наиболее частых и критичных по времени ожидания запросов PartitionKey должен быть включен как часть выражения запроса. Запрос, в котором указан PartitionKey, будет намного эффективнее, поскольку в этом случае просматриваются сущности только одной секции. Если при выполнении запроса PartitionKey не указан, в поисках необходимых сущностей просматриваются все секции таблицы, что значительно снижает эффективность.
Далее представлены некоторые советы и рекомендации по выбору PartitionKey для таблицы:
1.Прежде всего, выявите важные свойства таблицы. Это свойства, используемые в условиях запросов.
2.Из этих важных свойств выберите потенциальные ключи.
a.Из преобладающего запроса выберите свойства, используемые в условиях. Важно понять, какой запрос будет преобладающим для приложения.
b.Это будет исходный набор свойств ключей.
c.Расставьте свойства ключей в порядке их значимости в запросе.
3.Проверьте, обеспечивают ли свойства ключей уникальную идентификацию сущности? Если нет, включите в набор ключей уникальный идентификатор.
4.Если имеется только одно свойство ключа, используйте его в качестве
PartitionKey.
5.Если имеется только два свойства ключей, первое используйте как
ParitionKey и второе – как RowKey.
6.При наличии более двух свойств ключей можно попытаться распределить их
вдве группы: первая группа будет PartitionKey, и вторая – RowKey. При таком подходе приложение должно знать, что PartitionKey,
например, состоит из двух ключей, разделенных «-».
Теперь, когда приложение имеет набор потенциальных ключей, необходимо убедиться, что выбранная схема секционирования является масштабируемой:
1.Исходя из статистических данных интенсивности использования приложения, определите, не приведет ли секционирование по выбранному выше PartitionKey к созданию слишком загруженных секций, которые не смогут эффективно обслуживаться одним сервером? Проверить это можно, применив нагрузочное тестирование секции таблицы. Для этого в тестовой таблице создается секция соответственно выбранным ключам. Она подвергается пиковой нагрузке, полученной исходя из предполагаемых полезной нагрузки и запросов. Это позволяет проверить, может ли секция таблицы обеспечить необходимую производительность приложения.
2.Если секция таблицы проходит нагрузочное тестирование, ключи выбраны правильно.
3.Если секция таблицы не проходит нагрузочного тестирования, найдите ключ секции, который обеспечил бы более узкое подразделение сущностей. Это можно сделать через объединение выбранного ключа секции со следующим свойством ключа, или выбрав в качестве ключа секции другое важное свойство. Целью этой операции должно быть создание
81
большего количества секций, чтобы не возникало одной слишком большой или слишком загруженной секции.
4. Система спроектирована так, что обеспечивает необходимое масштабирование и обработку большого количества запросов. Но при чрезвычайно высокой интенсивности запросов ей приходится выполнять балансировку нагрузки, в результате чего некоторые из запросов могут завершаться ошибкой превышения времени ожидания. Сократить или устранить ошибки такого рода может снижение интенсивности запросов. Вообще говоря, такие ошибки возникают редко; однако если вы столкнулись с частыми или неожиданными ошибками превышения времени ожидания, свяжитесь с нами через сайт
MSDN, мы обсудим, как оптимизировать использование Windows Azure Table и предотвратить возникновение таких ошибок в вашем приложении.
Также можно проанализировать расширяемость выбранных ключей, особенно если на момент их выбора нет точных сведений о характеристиках пользовательского трафика. В этом случае важно выбирать ключи, которые можно легко расширять для обеспечения более тонкого секционирования. Далее в данном документе приводится подробный пример этого.
Для таблиц и сущностей поддерживаются следующие базовые операции:
Создание таблицы или сущности.
Извлечение таблицы или сущности с применением фильтров.
Обновление сущности (но не таблицы).
Удаление таблицы или сущности.
Для работы с таблицами в .NET-приложении можно просто использовать
ADO.NET Data Services.
Вследующей таблице приведен список предлагаемых API. Поскольку применение ADO.NET Data Services в итоге сводится к передаче REST-пакетов, приложения могут использовать REST напрямую. Кроме того, что REST обеспечивает возможность доступа
кхранилищу посредством не-.NET языков, он также позволяет реализовывать более тонкое управление сериализацией/десериализацией сущностей, что пригодится при работе с такими сценариями, как наличие разных типов сущностей или более чем 255 свойств в таблице и т.д.
Пример
Вприведенных ниже примерах описываются операции с таблицей «Blogs». В этой таблице хранятся блоги для приложения MicroBlogging.
Вприложении MicroBlogging есть две таблицы: Channels (Каналы) и Blogs (Блоги). Имеется список каналов, блоги публикуются в определенном канале. Пользователи подписываются на каналы и ежедневно получают новые блоги этих каналов.
Вданном примере рассмотрим только таблицу Blogs и приведем примеры следующих операций с ней:
1.Описание схемы таблицы
2.Создание таблицы
3.Вставка блога в таблицу
4.Получение списка блогов из таблицы
5.Обновление блога в таблице
6.Удаление блога из таблицы
Схема таблицы описывается как C#-класс. Такую модель использует ADO.NET Data Services. Схема известна только клиентскому приложению и упрощает доступ к данным. Сервер схему не применяет.
82
Рассмотрим описание сущностей Blog, хранящихся в таблице Blogs. Каждая сущность блога содержит следующие данные:
1.Имя канала (ChannelName) – канал, в котором размещается блог.
2.Дата размещения.
3.Текст (Text) – содержимое тела блога.
4.Рейтинг (Rating) – популярность этого блога.
Во-первых, обратите внимание, что для таблицы определен PartitionKey, представляющий имя канала, частью которого является блог, и в качестве RowKey используется дата размещения блога. PartitionKey и RowKey – ключи таблицы Blogs, они объявляются посредством атрибута класса DataServiceKey (Ключ сервиса данных). То есть таблица Blogs секционирована по именам каналов (ChannelName). Это позволяет приложению эффективно извлекать самые недавние блоги канала, на который подписан пользователь. Кроме ключей, в качестве свойств объявлены характерные для пользователя атрибуты. Все свойства имеют открытые (public) методы считывания и присвоения значения и хранятся в таблице Windows Azure Table. Итак, в примере ниже:
Text и Rating хранятся для экземпляра сущности в таблице Azure.
RatingAsString нет, потому что для него не определен метод присвоения значения.
Id не хранится, потому что методы доступа не public.
[DataServiceKey("PartitionKey", "RowKey")] public class Blog
{
// ChannelName
public string PartitionKey { get; set; } // PostedDate
public string RowKey { get; set; }
// Определяемые пользователем свойства public string Text { get; set; }
public int Rating { get; set; } public string RatingAsString { get; } protected string Id { get; set; }
}
Далее рассмотрим, как создать таблицу Blogs для учетной записи хранилища. Создание таблицы аналогично созданию сущности в основной таблице «Tables». Эта основная таблица определена для каждой учетной записи хранилища, и имя каждой таблицы, используемой учетной записью хранения, должно быть зарегистрировано в основной таблице. Описание класса основной таблицы приведено ниже, где свойство TableName (Имя таблицы) представляет имя создаваемой таблицы.
[DataServiceKey("TableName")] public class TableStorageTable
{
public string TableName { get; set; }
}
Фактическое создание таблицы происходит следующим образом:
// Uri сервиса: “http://<Account>.table.core.windows.net/” DataServiceContext context = new DataServiceContext(serviceUri); TableStorageTable table = new TableStorageTable("Blogs");
83
//Создаем новую таблицу, добавляя новую сущность
//в основную таблицу "Tables" context.AddObject("Tables", table);
//результатом вызова SaveChanges является отклик сервера
DataServiceResponse response = context.SaveChanges();
serviceUri – это uri сервиса таблицы, http://<Здесь указывается имя учетной записи>.table.core.windows.net/. DataServiceContext (Контекст сервиса данных) – один из основных классов сервиса данных ADO.NET, представляющий контекст времени выполнения для сервиса. Он обеспечивает API для вставки, обновления, удаления и запроса сущностей с помощью либо LINQ, либо RESTful URI и сохраняет состояние на стороне клиента.
Рассмотрим вставку элемента Blog. Чтобы вставить сущность, приложение должно выполнить следующее.
1.Создать новый C#-объект и задать все свойства.
2.Создать экземпляр DataServiceContext, который представляет подключение к серверу в сервисе данных ADO .NET для вашей учетной записи хранилища.
3.Добавить C#-объект в контекст.
4.Вызвать метод SaveChanges (Сохранить изменения) объекта DataServiceContext для отправки запроса серверу. Это обеспечивает отправку на сервер HTTPзапроса с сущностью в XML-формате ATOM.
Далее представлены примеры кода для перечисленных выше операций:
Blog blog = new Blog {
PartitionKey = "Channel9", // ChannelName
RowKey = DateTime.UtcNow.ToString(), // PostedDate Text = "Hello",
Rating = 3 };
serviceUri = new Uri("http://<account>.table.core.windows.net"); var context = new DataServiceContext(serviceUri); context.AddObject("Blogs", blog);
DataServiceContext response = context.SaveChanges();
Запрос сущностей выполняется с помощью встроенного в C# языка запросов LINQ (Language Integrated Query). В данном примере извлечем все блоги, рейтинг которых равен
3.
При обработке запроса (например, с помощью выражение foreach), он передается на сервер. Сервер отправляет результаты в XML-формате ATOM. Клиентская библиотека ADO .NET Data Services десериализует результаты в C#-объекты, после чего они могут использоваться приложением.
var serviceUri = new Uri("http://<account>.table.core.windows.net"); DataServiceContext context = new DataServiceContext(serviceUri);
//LINQ-запрос с использованием DataServiceContext для выбора
//из таблицы Blogs всех сущностей блогов, для которых rating = 3 var blogs =
from blog in context.CreateQuery<Blog>("Blogs") where blogs.Rating == 3
select blog;
//запрос отправляется на сервер и выполняется
foreach (Blog blog in blogs) { }
84
Обновление сущности выполняется следующим образом.
1.Создается DataContext (Контекст данных), свойству MergeOption (Вариант объединения) которого задается значение OverwriteChanges (Перезапись изменений) или PreserveChanges (Сохранение изменений), как описывается в разделе 4.8. Это обеспечивает правильную обработку ETag для каждого извлекаемого объекта.
2.С помощью LINQ DataContext получает сущность, которая будет обновляться. Извлечение ее с сервера гарантирует обновление ETag в сущностях, отслеживаемых контекстом, и то, что при последующих обновлениях и удалениях в заголовке if-match будет использоваться обновленный ETag. Меняем C#-объект, представляющий сущность.
3.Возвращаем C#-объект в тот же DataContext для обновления. Использование того же DataContext гарантирует автоматическое повторное использование ETag, полученного ранее для этого объекта.
4.Вызываем метод SaveChanges для отправки запроса на сервер.
Blog blog =
(from blog in context.CreateQuery<Blog>("Blogs") where blog.PartitionKey == "Channel9"
&& blog.RowKey == "Oct-29" select blog).FirstOrDefault(); blog.Text = "Hi there"; context.UpdateObject(blog);
DataServiceResponse response = context.SaveChanges(); 4.7 Удаление Blog
Удаление сущности аналогично ее обновлению. Для этого извлекаем сущность с помощью DataServiceContext и вызываем для содержимого вместо метода UpdateObject метод DeleteObject (Удалить объект).
// Получаем объект Blog для ("Channel9", "Oct-29") context.DeleteObject(blog);
DataServiceResponse response = context.SaveChanges();
Рассмотрим рекомендации по работе с DataServiceContext:
Объект DataServiceContext не обеспечивает безопасность потоков, поэтому он не может использоваться совместно разными потоками, а также имеет непродолжительное время существования.
DataServiceContext не является объектом с длительным временем жизни. Вместо того, чтобы использовать один DataServiceContext в течение всей жизни потока, рекомендуется создавать объект DataServiceContext каждый раз, когда возникает необходимость выполнить ряд транзакций с WindowsAzureTable, и затем удалять этот объект.
Если для всех вставок/обновлений/удалений используется один экземпляр DataServiceContext и возникает сбой при выполнении SaveChanges, сведения об операции, давшей сбой, сохраняются в DataServiceContext. При последующем вызове SaveChanges попытка выполнить эту операцию повторяется.
DataServiceContext имеет свойство MergeOption, которое используется для управления тем, как DataServiceContext обрабатывает отслеживаемые сущности. Возможные значения:
85
o AppendOnly (Только добавление): Это значение по умолчанию, при использовании которого DataServiceContext не загружает экземпляр сущности с сервера, если он уже имеется в его кэше.
o OverwriteChanges: DataServiceContext всегда загружает экземпляр сущности с сервера и перезаписывает предыдущий вариант сущности, т.е. обеспечивает соответствие экземпляра сущности ее текущему состоянию.
o PreserveChanges: Если экземпляр сущности существует в DataServiceContext, он не загружается из постоянного хранилища. Все изменения, вносимые в свойства объектов в DataServiceContext, сохраняются, но ETag обновляется, поэтому данную опцию следует использовать при необходимости восстановления после ошибок совместного доступа с нежесткой блокировкой.
oNoTracking (Без отслеживания): DataServiceContext не отслеживает экземпляры сущностей. Обновление сущности в контексте без отслеживания реализуется с помощью Etag, который обновляется посредством AttachTo. Этот вариант не рекомендуется к применению.
context.AttachTo("Blogs", blog, "etag to use"); context.UpdateObject(blog); context.SaveChanges();
Когда MergeOption контекста задано значение AppendOnly и объект DataServiceContext уже отслеживает сущность в результате предыдущей операции извлечения или добавления, повторное извлечение сущности с сервера не приведет к обновлению отслеживаемой сущности в контексте. Таким образом, если сущность на сервере была изменена, последующие обновления/удаления приведут к сбою необходимых условий (PreCondition). В примере кода раздела 5 MergeOption задано значение PreserveChanges, которое обеспечивает, что сущность будет загружаться с сервера всегда.
Результатом всех рассматриваемых выше операций является передача HTTPсообщений на и с сервера. Приложение может отказаться от использования клиентской библиотеки .NET и работать на уровне HTTP/REST.
Рассмотрим параллельные обновления. Для обновления сущности необходимо выполнить следующие операции.
1.Получить сущность с сервера
2.Обновить объект локально и вернуть его на сервер.
Предположим, два процесса, выполняющихся параллельно, пытаются обновить одну и ту же сущность. Поскольку шаги 1 и 2 не являются неделимыми, на любом из них может возникнуть ситуация внесения изменений в уже устаревшую версию сущности. Для решения этой проблемы Windows Azure Table использует нежесткую блокировку.
1.Для каждой сущности система сохраняет версию, которая изменяется сервером при каждом обновлении.
2.При извлечении сущности, сервер отправляет эту версию клиенту в виде
ETag HTTP.
3.Когда клиент передает запрос UPDATE (обновить) на сервер, он отправляет на него этот ETag в виде заголовка If-Match.
4.Если версия сущности, хранящаяся на сервере, аналогична ETag в заголовке If-Match, изменение принимается, и хранящаяся на сервере сущность
86