Немедленное и отложенное подтверждение

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

Немедленное подтверждение

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

  1. Подтвердите все RaiseEvent вызовы, использующиеся ConfirmEvents перед возвратом метода зерна.
  2. Убедитесь, что задачи, возвращаемые завершенными RaiseConditionalEvent до возврата метода зерна.
  3. Избегайте или AlwaysInterleaveAttribute избегайте ReentrantAttribute атрибутов, поэтому одновременно можно обрабатывать только один вызов зерна.

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

Потенциальные недостатки

  • Если подключение к удаленному кластеру или хранилищу временно прервано, то зерно становится недоступным: эффективно, зерно не может выполнить какой-либо код, пока он зависает, чтобы подтвердить события, что может занять неопределенное время (протокол согласованности журналов продолжает повторяться до восстановления подключения к хранилищу).

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

Отложенное подтверждение

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

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

Это означает, что код зерна может выполняться, пока некоторые события по-прежнему находятся в процессе подтверждения. API JournaledGrain<TGrainState,TEventBase> содержит некоторые конкретные положения, позволяющие разработчикам точно контролировать, как работать с неподтвержденными событиями, которые в настоящее время находятся в полете.

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

IEnumerable<EventType> UnconfirmedEvents { get; }

Кроме того, так как состояние, возвращаемое JournaledGrain<TGrainState,TEventBase>.State свойством, не включает эффект незавержденных событий, существует альтернативное свойство.

StateType TentativeState { get; }

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

Гарантии параллелизма

Обратите внимание, что Orleans гарантии планирования на основе поверх (совместного параллелизма) всегда применяются, даже если используется повторное выполнение или отложенное подтверждение. Это означает, что несмотря на то, что несколько методов могут выполняться, только один может активно выполняться— все остальные застряли в ожидании, поэтому никогда не существует истинных рас, вызванных параллельными потоками.

В частности, обратите внимание, что:

  • Свойства State, TentativeStateVersionи UnconfirmedEvents могут изменяться во время выполнения метода.
  • Но такие изменения могут произойти только в то время как застряли в ожидании.

Эти гарантии предполагают, что пользовательский код остается в рамках рекомендуемой практики по задачам и асинхронному/ожиданию (в частности, не использует задачи пула потоков или использует их только для кода, который не вызывает функциональные возможности зерна и которые должным образом ожидаются).