Транзакции и режимы блокировки в надежных коллекциях Azure Service Fabric

Транзакция

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

  • Атомарность: транзакция должна быть атомарной единицей работы. Другими словами, либо выполняются все изменения данных, либо не выполняется ни одно из них.
  • Согласованность. По завершении транзакция должна оставить все данные в согласованном состоянии. Все внутренние структуры данных должны быть правильными в конце транзакции.
  • Изоляция: изменения, внесенные параллельными транзакциями, должны быть изолированы от изменений, внесенных другими параллельными транзакциями. Уровень изоляции, используемый для операции в ITransaction , определяется IReliableState , выполняющей операцию.
  • Устойчивость: после завершения транзакции его эффекты постоянно сохраняются в системе. Изменения сохраняются даже в случае системного сбоя.

Уровни изоляции

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

  • Повторяемое чтение: Указывает, что выражения не могут считывать данные, которые были изменены, но еще не зафиксированы другими транзакциями, и что другие транзакции не могут изменять данные, которые были считаны текущей транзакцией, пока текущая транзакция не завершится.

    • Преимущества чтения повторяемых транзакций
      • Меньше использование памяти, чем в транзакциях моментальных снимков
      • Обеспечивает согласованный возврат значений для нескольких чтений в определённое время
    • Рекомендации по чтению повторяемых транзакций:
      • Записи блокируются при активном чтении данных

      • Операции чтения также блокируются во время активной записи данных.

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

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

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

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

Операция \ Роль Первичный Вторичный
Чтение отдельной сущности Повторяемое чтение Снимок
Перечисление, подсчёт Снимок Снимок

Примечание.

Примеры основных операций с одной сущностью: IReliableDictionary.TryGetValueAsync, IReliableQueue.TryPeekAsync.

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

Пример повторяемого поведения чтения

Надежные коллекции: Пример повторяемой изоляции при чтении

В этом примере видно, что T2 не может получить блокировку на K1 до тех пор, пока T1 не зафиксирует, так как T1 в данный момент удерживает блокировку чтения на ключе.

Пример поведения снимка

Пример изоляции моментальных снимков в Надежных коллекциях. Снимок экрана

В этом примере видно, что, несмотря на то, что T2 обновил значение K1 до V6, T2 по-прежнему перечисляет K1 как V1, при этом зная о собственном изменении K2. T3 не затрагивается, так как он считывает ключи, которые не имеют текущих блокировок записи.

Замки

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

Надежный словарь использует блокировку на уровне строк для всех операций с одной сущностью. Надежная очередь жертвует параллелизмом ради обеспечения строгого транзакционного свойства FIFO. В надёжной очереди используются блокировки уровня операций, позволяющие одновременно использовать одну транзакцию с TryPeekAsync и/или TryDequeueAsync, и одну транзакцию с EnqueueAsync. Обратите внимание, что для сохранения FIFO, если TryPeekAsync или TryDequeueAsync когда-либо обнаружат, что надежная очередь пуста, они также заблокируют EnqueueAsync.

Операции записи всегда устанавливают эксклюзивные блокировки. Для операций чтения блокировка зависит от нескольких факторов:

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

Матрица совместимости блокировки приведена в следующей таблице:

Запрос \ Разрешено Отсутствует Общее Обновление Исключительный
Общее Нет конфликтов Нет конфликтов Конфликт Конфликт
Обновление Нет конфликтов Нет конфликтов Конфликт Конфликт
Исключительный Нет конфликтов Конфликт Конфликт Конфликт

Аргумент времени ожидания в API Надежных коллекций используется для обнаружения взаимоблокировки. Например, две транзакции (T1 и T2) пытаются считывать и обновлять K1. Они могут взаимоблокироваться, потому что в конечном итоге оба имеют общую блокировку.

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

Дальнейшие действия