Как справиться с разделенным мозгом?

Я читал в Orleans FAQ, когда может произойти расщепление мозга, но я не понимаю, что плохого может случиться и как правильно с этим справиться.

FAQ говорит что-то расплывчатое вроде:

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

Но как на самом деле я должен это учитывать и что может случиться, если я не буду?

Орлеанский документ (http://research.microsoft.com/pubs/210931/Orleans-MSR-TR-2014-41.pdf) говорит следующее:

приложение может полагаться на внешнее постоянное хранилище для обеспечения более надежной согласованности данных

Но я не понимаю, что это значит.

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

Как они должны сохранять свои состояния? Может быть конфликт.

Когда другие экземпляры будут уничтожены и останется только один, что произойдет с состояниями уничтоженных экземпляров? Это будет похоже на то, что сообщения, обработанные ими, никогда не обрабатывались? Затем состояние клиента и состояние сервера можно было бы десинхронизировать IIUC.

Я вижу в этом (расщепление мозга) большую проблему и не понимаю, почему этому уделяется так мало внимания.


person bobby    schedule 07.02.2016    source источник


Ответы (1)


Orleans использует гарантии согласованности поставщика хранилища. Когда вы вызываете this.WriteStateAsync() из зерна, поставщик хранилища гарантирует, что зерно видело все предыдущие записи. Если это не так, генерируется исключение. Вы можете поймать это исключение и вызвать DeactivateOnIdle() и повторно создать исключение или вызвать ReadStateAsync() и повторить попытку. Итак, если у вас есть 2 гранулы во время сценария с разделенным мозгом, какая из них вызывает WriteStateAsync() первой, не позволяет другой записывать состояние, не прочитав сначала самое последнее состояние.

Обновление: начиная с Orleans v1.5.0, зерна, которое позволяет InconsistentStateException, который будет возвращен вызывающему абоненту, будет автоматически деактивирован после завершения текущих выполняемых вызовов. Зерно может catch и обрабатывать исключение, чтобы избежать автоматической деактивации.

person Reuben Bond    schedule 07.02.2016
comment
Правда ли, что выбрасывается исключение, и Orleans будет читать состояние, прежде чем позволить зерну обработать следующее сообщение? Как я вижу, InconsistentStateException не обрабатывается фреймворком. - person lmagyar; 08.02.2016
comment
@LaszloMagyar, ваше подозрение верно. Я открыл github.com/dotnet/orleans/issues/1420 и исправил отвечать. Спасибо :) - person Reuben Bond; 10.02.2016
comment
Это все еще не охватывает сценарий, в котором одно зерно получает сообщения только для чтения, а второе — сообщения для чтения/записи — первое будет отвечать устаревшими данными. - person shay__; 20.02.2016
comment
@shay__, правильно: вы должны заставить все методы выполнять чтение/запись из/в хранилище, если вам нужна согласованность. Непротиворечивые базы данных часто реплицируют операцию no-op, чтобы гарантировать, что они по-прежнему являются первичными экземплярами (существуют оптимизированные подходы, но суть та же). Точно так же, поскольку Orleans передает согласованность поставщику хранилища, вызов чтения/записи должен использоваться для обеспечения согласованности каждой операции, которая требует этого. - person Reuben Bond; 27.02.2016
comment
Поведение изменилось в v1.5.0, поэтому я обновил ответ, чтобы отразить это. - person Reuben Bond; 18.09.2017