Поделиться через


Разработка масштабируемой стратегии секционирования для хранилища таблиц Azure

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

Azure предоставляет облачное хранилище с высоким уровнем доступности и высокой масштабируемостью. Базовая система хранения для Azure предоставляется с помощью набора служб, включая хранилище BLOB-объектов Azure, хранилище таблиц Azure, хранилище очередей Azure и Файлы Azure.

Хранилище таблиц Azure предназначено для хранения структурированных данных. Служба хранилища Azure поддерживает неограниченное количество таблиц. Каждая таблица может масштабироваться до больших объемов и предоставлять терабайты физического хранилища. Чтобы наилучшим образом воспользоваться преимуществами таблиц, необходимо оптимально секционировать данные. В этой статье рассматриваются стратегии, которые можно использовать для эффективного секционирования данных для хранилища таблиц Azure.

Сущности таблицы

Сущности таблицы представляют единицы данных, хранящиеся в таблице. Сущности таблицы похожи на строки в типичной таблице реляционной базы данных. Каждая сущность задает набор свойств. Каждое свойство определяется как пара "ключ-значение" по имени, значению и типу данных значения. В рамках набора свойств сущности должны задавать следующие три системных свойства.

  • PartitionKey. Свойство PartitionKey хранит строковые значения, определяющие секцию, к которой принадлежит сущность. Секции, как мы обсудим далее, являются неотъемлемой частью масштабируемости таблицы. Сущности с одинаковым значением PartitionKey хранятся в одной секции.

  • RowKey. Свойство RowKey хранит строковые значения, которые однозначно идентифицируют сущности в каждой секции. PartitionKey и RowKey вместе образуют первичный ключ для сущности.

  • Timestamp: свойство Timestamp обеспечивает возможность трассировки для сущности. Метка времени — это значение даты и времени, указывающее время последнего изменения сущности. Метку времени иногда называют версией сущности. Изменения меток времени игнорируются, так как служба таблиц сохраняет значение этого свойства во время всех операций вставки и обновления.

Первичный ключ таблицы

Первичный ключ для сущности Azure состоит из объединенных свойств PartitionKey и RowKey . Эти два свойства образуют один кластеризованный индекс в таблице. Значения PartitionKey и RowKey могут содержать до 1024 символов. Пустые строки также разрешены; однако значения NULL не допускаются.

Кластеризованный индекс сортируется по PartitionKey в порядке возрастания, а затем по RowKey в порядке возрастания. Этот порядок сортировки соблюдается во всех ответах на запросы. Во время операции сортировки используются лексические сравнения. Строковое значение "111" отображается перед строковым значением "2". В некоторых случаях может потребоваться, чтобы порядок сортировки был числовым. Для сортировки в числовом и возрастающем порядке необходимо использовать строки с фиксированной длиной и заполненными нулевыми значениями. В предыдущем примере "002" отображается перед "111".

Разделы таблицы

Секции представляют коллекцию сущностей с одинаковыми значениями PartitionKey . Секции всегда обслуживаются с одного сервера секционирования. Каждый сервер секций может обслуживать одну или несколько секций. Сервер секционирования имеет ограничение скорости, касающееся числа сущностей из одной секции, которое он может обслуживать в течение некоторого времени. В частности, целевой показатель масштабируемости секции — 2000 сущностей в секунду. Эта пропускная способность может быть выше при минимальной нагрузке на узел хранилища, но она регулируется, когда узел становится горячим или активным.

Чтобы лучше проиллюстрировать концепцию секционирования, на следующем рисунке показана таблица, содержащая небольшое подмножество данных для регистрации событий гонки ног. На рисунке представлено концептуальное представление секционирования, где PartitionKey содержит три разных значения: название события в сочетании с тремя расстояниями (полный марафон, полумарафон и 10 км). В этом примере используются два сервера секционирования. Сервер A содержит регистрации для полумарафона и 10-километровых дистанций. Сервер B содержит только полные марафонские дистанции. Значения RowKey отображаются для предоставления контекста, но значения не имеют смысла в этом примере.

Схема, показывающая таблицу с тремя секциями
Таблица с тремя секциями

Масштабируемость

Поскольку секция всегда обслуживается с одного сервера секционирования, и каждый сервер секционирования может обслуживать одну или несколько секций, эффективность обслуживания сущностей зависит от работоспособности сервера. Серверы, которые сталкиваются с большим трафиком для своих секций, могут не поддерживать высокую пропускную способность. Например, на предыдущем рисунке, если получено много запросов на "2011 New York City Marathon__Half", сервер A может стать слишком горячим. Чтобы повысить пропускную способность сервера, система хранения выполняет балансировку нагрузки этих секций на другие сервера. В результате трафик распределяется по нескольким другим серверам. Для оптимальной балансировки нагрузки трафика следует использовать больше секций, чтобы хранилище таблиц Azure ранее пользовалось распределением секций на большее количество серверов секций.

Транзакции группы сущностей

Транзакция группы сущностей — это набор операций хранения, которые атомарно реализуются в сущностях с одинаковым значением PartitionKey . Если какая-либо операция хранения в группе сущностей завершается сбоем, выполняется откат всех операций хранения в сущности. Транзакция группы сущностей состоит не более чем из 100 операций хранения и может иметь размер не более 4 МиБ. Транзакции группы сущностей предоставляют хранилище таблиц Azure с ограниченной формой атомарности, согласованности, изоляции и устойчивости (ACID), предоставляемой реляционными базами данных.

Транзакции группы сущностей повышают пропускную способность, так как они сокращают количество отдельных операций хранилища, которые должны быть отправлены в хранилище таблиц Azure. Транзакции группы сущностей также обеспечивают экономическую выгоду. Транзакция группы сущностей оплачивается как одна операция хранения независимо от того, сколько операций хранения в ней содержится. Так как все операции хранения в транзакции группы сущностей влияют на сущности с одинаковым значением PartitionKey , необходимость использования транзакций группы сущностей может управлять выбором значения PartitionKey .

Секции диапазона

Если для сущностей используются уникальные значения PartitionKey , каждая сущность принадлежит к отдельной секции. Если используемые уникальные значения увеличиваются или уменьшаются, azure может создать секции диапазона. Секции диапазона группировали сущности с последовательными уникальными значениями PartitionKey для повышения производительности запросов диапазона. Без секций диапазона запрос диапазона должен пересекать границы секций или границы сервера, что может снизить производительность запросов. Рассмотрим приложение, использующее следующую таблицу с увеличивающимся значением последовательности для PartitionKey:

PartitionKey RowKey
"0001" -
"0002" -
"0003" -
"0004" -
"0005" -
"0006" -

Azure может сгруппировать первые три сущности в секцию диапазона. Если вы применяете запрос диапазона к таблице, которая использует PartitionKey в качестве условия и запрашивает сущности от "0001" до "0003", запрос может выполняться эффективно, так как сущности обслуживаются с одного сервера секционирования. Нет никакой гарантии, когда и как будет создана секция диапазона.

Наличие секций диапазона для таблицы может повлиять на производительность операций вставки при вставке сущностей с увеличивающимися или уменьшающимися значениями PartitionKey . Вставка сущностей с увеличивающимися значениями PartitionKey называется шаблоном только для добавления. Вставка сущностей с уменьшающимися значениями называется шаблоном только перед добавлением. Не используйте такие шаблоны, так как общая пропускная способность запросов на вставку ограничена одним сервером секционирования. Это связано с тем, что если секции диапазона существуют, первая и последняя (диапазон) секции содержат наименьшее и наибольшее значения PartitionKey соответственно. Таким образом, вставка новой сущности, которая имеет последовательно меньшее или более высокое значение PartitionKey , нацелена на одну из конечных секций. На следующем рисунке показан возможный набор секций диапазона, основанных на предыдущем примере. Если набор сущностей "0007", "0008" и "0009" был вставлен, они будут назначены последней (оранжевой) секции.

Схема, показывющая набор секций диапазона
Набор секций диапазона

Важно отметить, что не оказывает негативного влияния на производительность, если в операциях вставки используются более разрозненные значения PartitionKey .

Анализ данных

В отличие от таблицы в реляционной базе данных, которую можно использовать для управления индексами, таблицы в хранилище таблиц Azure могут иметь только один индекс. Индекс в хранилище таблиц Azure всегда состоит из свойств PartitionKey и RowKey .

В таблице Azure вы не можете настраивать производительность таблицы, добавляя дополнительные индексы или изменяя существующую таблицу после ее развертывания. При проектировании таблицы необходимо проанализировать данные. Наиболее важными аспектами, которые следует учитывать для оптимальной масштабируемости и эффективности запросов и вставки, являются значения PartitionKey и RowKey . В этой статье подчеркивается, как выбрать PartitionKey , так как он напрямую связан с секционированием таблиц.

Изменение размера секции

Размер секций определяется числом сущностей, содержащихся в секции. Как мы уже говорили в статье Масштабируемость, увеличение количества секций означает, что вы получаете более эффективную балансировку нагрузки. Степень детализации значения PartitionKey влияет на размер секций. На самом крупном уровне, если в качестве PartitionKey используется одно значение, все сущности находятся в одной очень большой секции. При высочайшем уровне детализации PartitionKey может содержать уникальные значения для каждой сущности. В результате для каждой сущности есть секция. В следующей таблице показаны преимущества и недостатки для диапазона детализации.

Степень детализации PartitionKey Размер секции Преимущества Недостатки
Однозначный Небольшое количество сущностей Пакетные транзакции возможны с любой сущностью.

Все сущности являются локальными и обслуживаются из одного узла хранилища.
Однозначный Большое количество сущностей Транзакции группы сущностей могут быть возможны с любой сущностью. Дополнительные сведения об ограничениях транзакций группы сущностей см. в разделе Выполнение транзакций группы сущностей. Масштабирование ограничено.

Пропускная способность ограничена производительностью одного сервера.
Несколько значений Несколько секций

Размеры секций зависят от распределения сущностей.
Пакетные транзакции возможны для некоторых сущностей.

Возможно динамическое секционирование.

Запросы с одним запросом возможны (без маркеров продолжения).

Возможна балансировка нагрузки между несколькими серверами секционирования.
Очень неравномерное распределение сущностей между секциями может ограничить производительность более крупных и активных секций.
Уникальные значения Много небольших секций Таблица является высокомасштабируемой.

Секции диапазона могут повысить производительность запросов между диапазонами секций.
Запросы, включающие диапазоны, могут потребовать посещения нескольких серверов.

Пакетные транзакции невозможны.

Шаблоны только при добавлении или только перед добавлением могут повлиять на пропускную способность вставки.

В таблице показано, как на масштабирование влияют значения PartitionKey . Рекомендуется использовать небольшие секции, так как они обеспечивают лучшую балансировку нагрузки. В некоторых сценариях могут быть уместны более крупные секции, и они не обязательно невыгодны. Например, если приложению не требуется масштабируемость, может потребоваться одна большая секция.

Определение запросов

Запросы извлекают данные из таблиц. При анализе данных для таблицы в хранилище таблиц Azure важно учитывать, какие запросы будет использовать приложение. Если приложение содержит несколько запросов, вам может потребоваться приоритизировать их, хотя ваши решения могут быть субъективными. Во многих случаях доминирующие запросы отличаются от других запросов. С точки зрения производительности запросы делятся на разные категории. Так как таблица содержит только один индекс, производительность запросов обычно связана со свойствами PartitionKey и RowKey . В следующей таблице показаны различные типы запросов и их оценки производительности.

Тип запроса Соответствие PartitionKey Соответствие RowKey Оценка производительности
Сканирование диапазона строк Exact Частично Лучше с секциями меньшего размера.

Плохо с очень большими секциями.
Сканирование диапазона секций Partial Partial Хорошо с небольшим количеством серверов секционирования, которые касаются.

Хуже с большими серверами касается.
Полное сканирование таблицы Частичное, отсутствует Частичное, отсутствует Хуже с подмножеством секций, которые проверяются.

Хуже всего при сканировании всех секций.

Примечание

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

Типы запросов, перечисленные в предыдущей таблице, показывают переход от лучших типов запросов к наихудшим типам на основе их оценок производительности. Точечные запросы — это лучшие типы запросов, поскольку полностью используют кластеризованный индекс таблицы. В следующем запросе используются данные из таблицы регистрации гонок для ног:

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)  
  

Если приложение использует несколько запросов, не все из них могут быть точечными запросами. С точки зрения производительности запросы в диапазоне следуют за точечными запросами. Существует два типа запросов диапазона: проверка диапазона строк и проверка диапазона секций. Сканирование диапазона строк определяет одну секцию. Так как операция выполняется на сервере с одним разделом, сканирование диапазона строк обычно более эффективно, чем сканирование диапазона секций. Однако ключевым фактором, определяющим производительность сканирования диапазона строк, является выборка запроса. Избирательность запроса определяет, по скольким строкам необходимо выполнить итерацию, чтобы найти соответствующие строки. Более избирательные запросы являются более эффективными при сканировании диапазона строк.

Чтобы оценить приоритеты запросов, рассмотрите требования к частоте и времени отклика для каждого запроса. Часто выполняемые запросы могут иметь более высокий приоритет. Однако важный, но редко используемый запрос может иметь требования к низкой задержке, которые могут ранжировать его выше в списке приоритетов.

Выбор значения PartitionKey

Основой структуры любой таблицы являются масштабируемость, запросы, используемые для доступа к ней, и требования к операции хранения. Выбранные значения PartitionKey определяют способ секционирования таблицы и тип запросов, которые можно использовать. Операции хранилища и особенно операции вставки также могут повлиять на выбор значений PartitionKey . Значения PartitionKey могут варьироваться от отдельных значений до уникальных значений. Их также можно создать с помощью нескольких значений. Для формирования значения PartitionKey можно использовать свойства сущности. Или приложение может вычислить значение . В следующих разделах рассматриваются важные вопросы.

Транзакции группы сущностей

Разработчикам следует сначала подумать о том, будет ли приложение использовать транзакции группы сущностей (пакетные обновления). Для транзакций группы сущностей требуется, чтобы у сущностей было одинаковое значение PartitionKey . Кроме того, так как пакетные обновления предназначены для всей группы, выбор значений PartitionKey может быть ограничен. Например, банковское приложение, поддерживающее операции с наличными средствами, должно вставлять такие операции в таблицу автоматически, Денежные операции представляют как дебетовую, так и кредитную стороны и должны быть чистые до нуля. Это требование означает, что номер учетной записи нельзя использовать в качестве части значения PartitionKey , так как каждая сторона транзакции использует разные номера счетов. Вместо этого лучше выбрать идентификатор транзакции.

Секции

Номера и размеры секций влияют на масштабируемость таблицы, которая находится под нагрузкой. Они также управляются степенью детализации значений PartitionKey . Определить PartitionKey на основе размера секции может быть сложно, особенно если распределение значений трудно предсказать. Общее правило заключается в том, чтобы использовать много секций небольшого размера. Многие секции таблиц упрощают для хранилища таблиц Azure управление узлами хранилища, с помощью которых обслуживаются секции.

Выбор уникальных или более тонких значений для PartitionKey приводит к уменьшению, но к большему числу секций. Обычно это выгодно, так как система может распределять нагрузку между несколькими секциями, чтобы распределить нагрузку между несколькими секциями. Однако необходимо проанализировать, какое влияние может оказать большое число секций на производительность межсекционных запросов в диапазоне. Эти типы запросов должны посещать несколько секций, чтобы удовлетворить запрос. Возможно, секции распределены между несколькими серверами секционирования. Если запрос пересекает границы сервера, необходимо возвращать маркеры продолжения. Маркеры продолжения указывают следующие значения PartitionKey или RowKey , чтобы получить следующий набор данных для запроса. Другими словами, маркеры продолжения представляют по крайней мере еще один запрос к службе, что может снизить общую производительность запроса.

Другим фактором, который может влиять на производительность запроса, является избирательность запроса. Избирательность запроса показывает, по скольким строкам необходимо выполнить итерацию для каждой секции. Чем выборочнее запрос, тем эффективнее он возвращает нужные строки. Общая производительность запросов к диапазону может зависеть от количества серверов секционирования, которые необходимо коснуться, или от выборочной выборки запроса. Кроме того, при вставке данных в таблицу следует избегать использования шаблонов только для добавления или добавления в начало. При использовании этих шаблонов, несмотря на создание небольших и многочисленных секций, можно ограничить пропускную способность операций вставки. Шаблоны только для добавления и только при добавлении рассматриваются в разделе Секции диапазона.

Запросы

Знание запросов, которые вы будете использовать, поможет определить, какие свойства важны для значения PartitionKey . Свойства, используемые в запросах, являются кандидатами на значение PartitionKey . В следующей таблице приведены общие рекомендации по определению значения PartitionKey .

Если сущность… Действие
Имеет одно ключевое свойство Используйте его в качестве PartitionKey.
Имеет два ключевых свойства Используйте один из них в качестве PartitionKey , а другой — в качестве RowKey.
Имеет более двух ключевых свойств Используйте составной ключ из объединенных значений.

При наличии нескольких одинаково доминирующих запросов можно вставить данные несколько раз, используя разные необходимые значения RowKey . Приложение будет управлять вторичными (или третичными и т. д.) строками. Этот тип шаблона можно использовать для удовлетворения требований к производительности запросов. В следующем примере используются данные из примера регистрации гонки ног. Он содержит два основных запроса:

  • запрос по нагрудному номеру;
  • запрос по возрасту.

Для обслуживания обоих доминантных запросов вставьте две строки в качестве транзакции группы сущностей. В следующей таблице показаны свойства PartitionKey и RowKey для этого сценария. Значения RowKey предоставляют префикс для биб-файла и возраста, что позволяет приложению различать два значения.

PartitionKey RowKey
2011 New York City Marathon__Full BIB:01234__John__M__55
2011 New York City Marathon__Full AGE:055__1234__John__M

В этом примере возможна транзакция группы сущностей, так как значения PartitionKey совпадают. Групповая транзакция обеспечивает атомарность операции вставки. Хотя этот шаблон можно использовать с разными значениями PartitionKey , мы рекомендуем использовать те же значения, чтобы получить это преимущество. В противном случае может потребоваться написать дополнительную логику, чтобы обеспечить атомарные транзакции, использующие разные значения PartitionKey .

Операции с хранилищем

Таблицы в хранилище таблиц Azure могут столкнуться с нагрузкой не только из запросов. Они также могут столкнуться с нагрузкой от операций хранилища, таких как вставка, обновление и удаление. Определите, какой тип операций хранения вы будете выполнять с таблицей и с какой скоростью. Если вы выполняете эти операции редко, возможно, вам не придется беспокоиться о них. Однако для частых операций, таких как выполнение большого количества операций вставки за короткое время, необходимо учитывать, как эти операции выполняются в результате выбора значений PartitionKey . Важными примерами являются шаблоны только для добавления и только перед добавлением. Шаблоны только для добавления и только при добавлении рассматриваются в разделе Секции диапазона.

При использовании шаблона только для добавления или только в начале используются уникальные значения по возрастанию или убыванию для PartitionKey при последующих вставке. Если вы объедините этот шаблон с частыми операциями вставки, таблица не сможет обслуживать операции вставки с большой масштабируемостью. Масштабируемость таблицы зависит от того, что Azure не может сбалансировать нагрузку на запросы операций к другим серверам секционирования. В этом случае может потребоваться использовать случайные значения, например значения GUID. Затем размеры секций могут оставаться небольшими и по-прежнему поддерживать балансировку нагрузки во время операций с хранилищем.

Нагрузочное тестирование секции таблицы

Если значение PartitionKey является сложным или требует сравнения с другими сопоставлениями PartitionKey , может потребоваться проверить производительность таблицы. Тест должен проверить, насколько хорошо работает секционирование при пиковых нагрузках.

Для выполнения нагрузочного теста выполните следующие действия.

  1. Создайте тестовую таблицу.
  2. Загрузите тестовую таблицу с данными, чтобы она содержала сущности, имеющие целевое значение PartitionKey .
  3. Используйте приложение для имитации пиковой нагрузки в таблицу. Нацелим на одну секцию, используя значение PartitionKey из шага 2. Этот шаг отличается для каждого приложения, но моделирование должно включать все необходимые запросы и операции хранения. Может потребоваться настроить приложение таким образом, чтобы оно было предназначено для одной секции.
  4. Исследуйте пропускную способность операций GET или PUT в таблице.

Для этого сравните фактические значения с указанным ограничением одной секции на одном сервере. Секции ограничены 2000 сущностями в секунду. Если пропускная способность секции превышает 2000 сущностей в секунду, сервер может работать слишком активно в рабочей среде. В этом случае значения PartitionKey могут быть слишком грубыми, поэтому секций недостаточно или они слишком велики. Возможно, потребуется изменить значение PartitionKey , чтобы секции распределялись между несколькими серверами.

балансировка нагрузки;

Балансировка нагрузки на уровне секционирования происходит, когда секция становится слишком горячей. Если секция слишком горяча, секция, в частности сервер секций, выходит за рамки своей целевой масштабируемости. Для службы хранилища Azure каждая секция имеет целевой показатель масштабируемости 2000 сущностей в секунду. Балансировка нагрузки также выполняется на уровне распределенной файловой системы (DFS).

Балансировка нагрузки на уровне DFS связана с нагрузкой ввода-вывода и находится вне область этой статьи. Балансировка нагрузки на уровне секционирования не выполняется сразу после превышения целевого показателя масштабируемости. Вместо этого система ожидает несколько минут, прежде чем начать процесс балансировки нагрузки. Это гарантирует, что секция действительно начала испытывать высокую нагрузку. Нет необходимости создавать основные секции с созданной нагрузкой, которая активирует балансировку нагрузки, так как система автоматически выполняет задачу.

Если таблица была загрунтирована с определенной нагрузкой, система может сбалансировать секции на основе фактической нагрузки, что приводит к значительно отличающейся распределению секций. Вместо подготовки секций рекомендуется написать код, обрабатывающий ошибки времени ожидания и занято сервером. Ошибки возвращаются, когда система выполняет балансировку нагрузки. Обрабатывая эти ошибки с помощью стратегии повторных попыток, приложение может лучше обрабатывать пиковые нагрузки. Стратегии повторов подробно рассматриваются в следующем разделе.

При выполнении балансировки нагрузки секция переходит в автономный режим на несколько секунд. В автономном режиме система переназначает секцию другому серверу секций. Важно отметить, что ваши данные не хранятся на серверах секций. Они обслуживают сущности на уровне DFS. Так как данные не хранятся на уровне секционирования, перемещение секций на разные серверы — это быстрый процесс. Такая гибкость значительно ограничивает время простоя приложения, если таковое может возникнуть.

Стратегия повторов

Для приложения важно обрабатывать сбои операций хранения, чтобы гарантировать, что вы не потеряете обновления данных. Для некоторых сбоев не требуется стратегия повтора. Например, обновления, возвращающие ошибку 401 Unauthorized, не выиграют от повторной попытки операции, так как вполне вероятно, что состояние приложения не изменится между повторными попытками, которые устраняют ошибку 401. Однако такие ошибки, как "Занят сервер" или "Время ожидания", связаны с функциями балансировки нагрузки Azure, обеспечивающими масштабируемость таблиц. Когда узлы хранилища, обслуживающие сущности, становятся горячими, Azure распределяет нагрузку, перемещая секции на другие узлы. В течение этого времени секция может быть недоступна, что приводит к ошибкам "Занят сервер" или "Время ожидания". В конечном итоге секция будет повторно включена, и обновления возобновляются.

Стратегия повторных попыток подходит для ошибок "Занят сервер" или "Время ожидания". В большинстве случаев из логики повторных попыток можно исключить ошибки 400 уровня и около 500 уровней. Ошибки, которые можно исключить, включают 501 Not Implemented и 505 HTTP Version Not Supported. Затем можно реализовать стратегию повторных попыток для ошибок до 500, таких как "Занят сервер" (503) и "Время ожидания" (504).

Вы можете выбрать один из трех распространенных стратегий повторных попыток для приложения:

  • Нет повторных попыток: попытка повтора не выполняется.
  • Исправлена задержка. Операция повторно выполняется N раз с постоянным значением backoff.
  • Экспоненциальная задержка. Операция повторно выполняется N раз с экспоненциальным значением задержки.

Стратегия "Не повторять" — это простой (и половинчатый) способ обработки сбоев операций. Однако стратегия "Без повтора" не очень полезна. Если не предпринимаются никакие попытки повтора, то существуют очевидные риски, что после неудачной операции данные не будут правильно сохранены. Лучшая стратегия — использовать стратегию фиксированной задержки. предоставляет возможность повторного выполнения операций с той же продолжительностью задержки.

Однако стратегия не оптимизирована для обработки высокомасштабируемых таблиц. Если многие потоки или процессы ожидают одинаковое время, могут возникнуть конфликты. Рекомендуемая стратегия повторных попыток — это стратегия, в которой используется экспоненциальная задержка, при которой каждая попытка повтора длится дольше последней попытки. Это похоже на алгоритм предотвращения конфликтов, используемый в компьютерных сетях, таких как Ethernet. Экспоненциальная задержка с помощью случайного фактора обеспечивает дополнительное отклонение от итогового интервала. Затем значение задержки ограничивается минимальным и максимальным значением. Для вычисления следующего значения задержки с помощью экспоненциального алгоритма можно использовать следующую формулу:

y = Rand(0,8z, 1,2z)(2x-1

y = Min(zmin + y, zmax

Где:

z — задержка по умолчанию в миллисекундах;

zmin — минимальная задержка по умолчанию в миллисекундах;

zmax — максимальная задержка по умолчанию в миллисекундах;

x — число повторов;

y — значение задержки в миллисекундах.

Множители 0,8 и 1,2, используемые в функции Rand (random), создают случайную дисперсию отката по умолчанию в пределах ±20 % от исходного значения. Диапазон ±20 % приемлем для большинства стратегий повтора и предотвращает дальнейшие конфликты. Формулу можно реализовать с помощью следующего кода:

int retries = 1;  
  
// Initialize variables with default values  
var defaultBackoff = TimeSpan.FromSeconds(30);  
var backoffMin = TimeSpan.FromSeconds(3);  
var backoffMax = TimeSpan.FromSeconds(90);  
  
var random = new Random();  
  
double backoff = random.Next(  
    (int)(0.8D * defaultBackoff.TotalMilliseconds),   
    (int)(1.2D * defaultBackoff.TotalMilliseconds));  
backoff *= (Math.Pow(2, retries) - 1);  
backoff = Math.Min(  
    backoffMin.TotalMilliseconds + backoff,   
    backoffMax.TotalMilliseconds);  
  

Сводка

Приложение в хранилище таблиц Azure может хранить большой объем данных, так как хранилище таблиц управляет секциями на нескольких узлах хранилища и переназначает их. Для управления масштабируемостью таблицы можно использовать секционирование данных. Планируйте заранее при определении схемы таблицы, чтобы обеспечить реализацию эффективных стратегий секционирования. В частности, проанализируйте требования, данные и запросы приложения, прежде чем выбирать значения PartitionKey . Каждую секцию можно переназначить разным узлам хранилища, так как система реагирует на трафик. Используйте нагрузочный тест секции, чтобы убедиться, что таблица имеет правильные значения PartitionKey . Этот тест помогает определить, когда секции слишком горячие, и внести необходимые корректировки.

Чтобы убедиться, что приложение обрабатывает периодические ошибки и данные сохраняются, используйте стратегию повторных попыток с задержкой. Политика повторных попыток по умолчанию, которую использует клиентская библиотека службы хранилища Azure, имеет экспоненциальную задержку, которая позволяет избежать конфликтов и максимально увеличить пропускную способность приложения.