Инструкции и рекомендации для надежных коллекций в Azure Service Fabric

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

Надежные гильдии коллекции

Инструкции составлены как простые рекомендации со словами Делайте, Постарайтесь, Избегайте и Не делайте в начале.

  • Не изменяйте объекты пользовательского типа, возвращаемые операциями чтения (например, TryPeekAsync или TryGetValueAsync). Надежные коллекции, как и параллельные коллекции, возвращают ссылку на объект, а не его копию.
  • Обязательно создайте глубокую копию возвращенного объекта пользовательского типа, прежде чем изменять этот объект. Поскольку структуры и встроенные типы передаются по значению, вам необязательно создавать их глубокую копию, если они не содержат поля или свойства со ссылками, которые вы собираетесь изменить.
  • Не используйте TimeSpan.MaxValue для времени ожидания. Время ожидания следует использовать для определения взаимоблокировок.
  • Не используйте транзакцию после того, как она была зафиксирована, прервана или удалена.
  • Не используйте перечисление за пределами области транзакции, в которой оно было создано.
  • Не создавайте транзакцию в операторе using другой транзакции, так как это может привести к взаимоблокировке.
  • Не создавайте надежное состояние с помощью IReliableStateManager.GetOrAddAsync и используйте надежное состояние в одной транзакции. Это приведет к исключению InvalidOperationException.
  • Убедитесь, что реализация IComparable<TKey> правильна. Система использует соответствующую зависимость IComparable<TKey> для слияния контрольных точек и строк.
  • Используете блокировку изменения при чтении элемента с целью обновить его, чтобы предотвратить взаимоблокировки определенного класса.
  • Рекомендуем использовать менее 1000 надежных коллекций на раздел. Лучше использовать большее количество элементов в надежных коллекциях, чем большее количество надежных коллекций с меньшим количеством элементов.
  • Постарайтесь поддерживать размер элементов (например, TKey + TValue для надежного словаря) до 80 КБ: чем меньше, тем лучше. Это позволит уменьшить объем использования кучи больших объектов, а также снизить требования к дискам и сетевым операциям ввода-вывода. Часто это также помогает уменьшить репликацию повторяющихся данных при обновлении только небольшой части значения. Распространенный способ добиться этого в надежном словаре — разбить строки на несколько строк.
  • Возможно, вас заинтересует применение функций архивации и восстановления для аварийного восстановления.
  • Избегайте совместного использования операций с одной сущностью и операций с несколькими сущностями (например, GetCountAsync, CreateEnumerableAsync) в одной и той же транзакции ввиду различных уровней изоляции.
  • Обработайте исключение InvalidOperationException. Пользовательские транзакции могут быть прерваны системой по разным причинам. Например, если диспетчер надежных состояний изменяет свою роль с основной на какую-то другую, или когда транзакция с длительным временем выполнения блокирует усечение журнала транзакций. В таких случаях пользователь может получить исключение InvalidOperationException, указывающее на то, что его транзакция уже завершена. Если предположить, что завершение транзакции не было запрошено пользователем, то лучший способ обработки этого исключения — удалить транзакцию и проверить, не получен ли сигнал в виде токена отмены (или изменена роль реплики). И если нет, то создать новую транзакцию и повторить попытку.
  • Не применяйте параллельные или параллельные операции в транзакции. В транзакции поддерживается только одна операция потока пользователя. В противном случае это приведет к утечке памяти и проблемам с блокировкой.
  • Рассмотрите возможность удаления транзакции как можно скорее после завершения фиксации (особенно при использовании ConcurrentQueue).
  • Не выполняйте блокирующий код внутри транзакции.
  • Если строка используется в качестве ключа для надежного словаря, порядок сортировки использует сравнение строк по умолчанию CurrentCulture. Обратите внимание, что порядок сортировки CurrentCulture отличается от порядкового сравнения строк.
  • Не удаляйте или отменяйте фиксацию транзакции. Это не поддерживается и может завершиться процессом узла.
  • Убедитесь, что порядок операций разных словарей остается одинаковым для всех параллельных транзакций при чтении или написании нескольких словарей, чтобы избежать взаимоблокировки.

При этом нужно помнить о следующем:

  • Время ожидания по умолчанию составляет 4 секунды для всех API надежных коллекций. Большинство пользователей должны использовать время ожидания по умолчанию.
  • Во всех API надежных коллекций токеном отмены по умолчанию является CancellationToken.None .
  • Параметр типа ключа (TKey) для надежного словаря должен правильно реализовывать GetHashCode() и Equals(). Ключи должны быть неизменяемыми.
  • Чтобы обеспечить высокую доступность надежных коллекций, в каждой службе необходимый и минимальный размер набора реплик должен быть равен как минимум 3.
  • Операции чтения в базе данных-получателе могут считывать версии без кворума. Это означает, что версия данных, считываемая из отдельной базы данных-получателя, может быть ложно увеличена. Чтение из базы данных-источника всегда стабильно и не может вызывать ложное увеличение номера версии.
  • Безопасность и конфиденциальность данных, хранимых приложением в надежной коллекции, зависит от вашего решения и средств, предоставляемых управлением хранилищем. Например, можно использовать шифрование дисков операционной системы для защиты неактивных данных.
  • Перечисление ReliableDictionary использует отсортированную структуру данных, упорядоченную по ключу. Чтобы сделать перечисление эффективным, фиксации добавляются во временную хэш-таблицу и затем перемещаются в основную отсортированную структуру данных после контрольной точки. Операции добавления, обновления и удаления имеют лучшее время выполнения O(1) и худшее время выполнения O(log n) в случае проверки наличия ключа. Операции Get могут иметь сложность O(1) или O(log n) в зависимости от того, выполняется ли чтение из последней фиксации или из более старой фиксации.

Дополнительные рекомендации по переменным надежным коллекциям

При принятии решения о работе с непостоянными надежными коллекциями учитывайте следующее:

  • ReliableDictionary поддерживает непостоянные коллекции.
  • ReliableQueue поддерживает непостоянные коллекции.
  • ReliableConcurrentQueue НЕ поддерживает непостоянные коллекции.
  • Хранимые службы НЕЛЬЗЯ сделать непостоянными. После изменения флага HasPersistedState на false необходимо повторно создать всю службу с нуля.
  • Непостоянные службы НЕЛЬЗЯ сделать хранимыми. После изменения флага HasPersistedState на true необходимо повторно создать всю службу с нуля.
  • HasPersistedState — это конфигурация уровня службы. Это означает, что ВСЕ коллекции будут либо хранимыми, либо временными. Использовать и непостоянные, и хранимые коллекции нельзя.
  • Потеря кворума в результатах непостоянной секции приводит к полной потере данных.
  • Функции резервного копирования и восстановления НЕДОСТУПНЫ для непостоянных служб.

Следующие шаги