Общие сведения о надежных субъектах Service Fabric

Субъекты Reliable Actors — это платформа приложений Service Fabric, основанная на шаблоне виртуальных субъектов. API субъектов Reliable Actors предоставляет однопоточную модель программирования, основанную на той надежности и масштабируемости, которые гарантирует Service Fabric.

Что представляют собой субъекты?

Субъект — это изолированная, независимая единица вычислений и состояния с однопоточным выполнением. Шаблон субъектов — это модель вычислений для параллельных или распределенных систем, в которой несколько субъектов могут выполняться одновременно и независимо друг от друга. Субъекты могут взаимодействовать друг с другом и создавать новые субъекты.

Когда следует использовать субъекты Reliable Actors

Субъекты Reliable Actors Service Fabric — это реализация шаблона проектирования субъектов. Как и в случае с любым другим шаблоном проектирования программного обеспечения, решение о выборе того или иного шаблона зависит от того, соответствует ли он проблеме проектирования программного обеспечения.

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

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

Субъекты в Service Fabric

В Service Fabric субъекты реализуются на платформе субъектов Reliable Actors: платформа приложений на основе шаблона субъекта опирается на службы Reliable Services Service Fabric. Каждая написанный вами субъект Reliable Actor фактически представляет собой секционированную надежную службу Reliable Service с отслеживанием состояния.

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

Срок действия субъекта

Субъекты Service Fabric виртуальные. Это означает, что срок их действия не привязан к их представлению в памяти. В результате их не требуется создавать и удалять в явном виде. Получив запрос с идентификатором субъекта, среда выполнения субъектов Reliable Actors автоматически активирует соответствующий субъект. Если субъект не используется в течение определенного времени, среда выполнения субъектов Reliable Actors удаляет выполняемый в памяти объект как мусор. Существование субъекта также будет учитываться на случай необходимости в его повторной активации в будущем. Дополнительные сведения см. в статье Жизненный цикл субъектов и сбор мусора.

Это абстрактное представление жизненного цикла виртуальных субъектов включает ряд предупреждений, связанных с моделью виртуальных субъектов; время от времени реализация субъектов Reliable Actors отклоняется от этой модели.

  • Как только на идентификатор субъекта отправляется сообщение, этот субъект автоматически активируется (и формируется объект субъекта). По прошествии определенного периода времени объект субъекта удаляется. В дальнейшем, если идентификатор этого субъекта используется снова, формируется новый объект субъекта. Если состояние субъекта сохраняется в диспетчере состояний, оно хранится дольше, чем жизненный цикл объекта.
  • Вызов любого метода субъекта с идентификатором субъекта активирует этот субъект. По этой причине среда выполнения неявно вызывает конструктор соответствующих типов субъектов. Таким образом, код клиента не может передать параметры в конструктор типа субъекта, хотя параметры могут передаваться в конструктор субъекта самой службой. В результате, если субъекту требуются параметры инициализации от клиента, к моменту вызова других методов он может быть сформирован в частично инициализированном состоянии. Ни одной точки входа для активации субъекта со стороны клиента нет.
  • Несмотря на то, что субъекты Reliable Actors неявно создают объекты, напрямую удалить субъект и его состояние нельзя.

Распространение и отработка отказа

Для обеспечения масштабируемости и надежности Service Fabric распределяет субъекты по кластеру и автоматически переносит их с неисправных узлов в работоспособные по мере необходимости. Это абстрактное представление секционированной службы Reliable Service с отслеживанием состояния. Распределение, масштабируемость, надежность и автоматическая отработка отказа достигаются благодаря тому, что субъекты выполняются в службе Reliable Services с отслеживанием состояния, которая называется службой субъектов.

Субъекты распределяются по секциям службы субъектов, а секции — по узлам в кластере Service Fabric. Каждая секция службы содержит набор субъектов. Service Fabric управляет распространением этих секций и отработкой отказа, если в них возникают сбои.

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

Распространение субъектов Reliable Actors

Схемой разделов и параметрами диапазона ключей управляет платформа субъектов. Это упрощает работу, но требует внимания к следующим моментам:

  • Службы Reliable Services позволяют выбрать схему секционирования, диапазон ключей (если используется схема секционирования по диапазону) и количество разделов. Субъекты Reliable Actors ограничиваются схемой секционирования по диапазону (универсальной схемой Int64) и требуют полного диапазона ключей Int64.
  • По умолчанию субъекты равномерно распределяются между секциями в случайном порядке.
  • Поскольку субъекты размещаются случайным образом, для выполняемых ими операций, включая сериализацию и десериализацию данных по вызовам методов, задержкам и нагрузке, всегда будет требоваться подключение к сети.
  • В более сложных сценариях размещение субъектов в секциях можно контролировать, сопоставляя идентификаторы субъектов Int64 с определенными секциями, однако это может привести к неравномерному распределению субъектов между секциями.

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

Обмен данными с субъектами

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

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

Прокси-объект субъекта

Клиентский API субъектов Reliable Actors обеспечивает обмен данными между клиентом и экземпляром субъекта. Для обмена данными с субъектом клиент создает для него прокси-объект, реализующий интерфейс субъекта. Клиент взаимодействует с субъектом, вызывая методы через прокси-объект. Прокси-объект субъекта можно использовать для обмена данными как между клиентом и субъектом, так и между субъектами.

// Create a randomly distributed actor ID
ActorId actorId = ActorId.CreateRandom();

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
IMyActor myActor = ActorProxy.Create<IMyActor>(actorId, new Uri("fabric:/MyApp/MyActorService"));

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
await myActor.DoWorkAsync();
// Create actor ID with some name
ActorId actorId = new ActorId("Actor1");

// This only creates a proxy object, it does not activate an actor or invoke any methods yet.
MyActor myActor = ActorProxyBase.create(actorId, new URI("fabric:/MyApp/MyActorService"), MyActor.class);

// This will invoke a method on the actor. If an actor with the given ID does not exist, it will be activated by this method call.
myActor.DoWorkAsync().get();

Обратите внимание на два фрагмента данных, используемых для создания прокси-объекта субъекта. Это идентификатор субъекта и имя приложения. Идентификатор субъекта однозначно определяет субъект, а имя приложения определяет приложение Service Fabric, в котором развернут субъект.

Класс ActorProxy(C#) или ActorProxyBase(Java) на стороне клиента выполняет необходимое разрешение, чтобы найти субъект по идентификатору и открыть канал связи с ним. Он также повторяет попытку поиска субъекта при сбоях связи и отработках отказов. В результате доставка сообщений имеет следующие характеристики:

  • Доставка сообщений не гарантируется.
  • Субъекты могут получать дубликаты сообщений от одного и того же клиента.

Параллелизм

В среде выполнения субъектов Reliable Actors для доступа к методам субъектов используется простая модель поочередности. Это означает, что в конкретный момент времени в коде объекта субъекта может быть активен только один поток. Поочередный доступ значительно упрощает параллельные системы, поскольку снимает необходимость в механизмах синхронизации для доступа к данным. Это также означает, что системы нужно проектировать с учетом однопоточного доступа для каждого экземпляра субъекта.

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

Обмен данными между субъектами Reliable Actors

Поочередный доступ

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

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

Проиллюстрируем эти понятия на примере. Рассмотрим тип субъекта, который реализует два асинхронных метода (назовем их Method1 и Method2), таймер и напоминание. На схеме ниже показана временная шкала выполнения этих методов и обратных вызовов от имени субъектов ActorId1 и ActorId2, относящихся к этому типу субъекта.

Доступ и пошаговый параллелизм в среде выполнения Reliable Actors

В схеме используются следующие обозначения:

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

Необходимо учитывать следующие важные моменты.

  • Когда выполняется Method1 от имени субъекта ActorId2 в ответ на запрос клиента xyz789, поступает другой запрос от клиента abc123, который тоже требует выполнения метода Method1 субъектом ActorId2. Выполнение второго метода Method1 не начинается до завершения первого. Аналогичным образом напоминание, зарегистрированное субъектом ActorId2, срабатывает во время выполнения метода Method1 в ответ на запрос клиента xyz789. Обратный вызов по напоминанию будет выполнен только после того, как оба метода Method1 будут выполнены. Такое поведение обусловлено тем, что для субъекта ActorId2работает принцип поочередного параллелизма.
  • Кроме того, этот принцип применяется для субъекта ActorId1. Это видно по последовательному выполнению методов Method1 и Method2, а также обратного вызова по таймеру от имени субъекта ActorId1.
  • Выполнение метода Method1 от имени субъекта ActorId1 перекрывается с выполнением того же метода от имени субъекта ActorId2. Это связано с тем, что пошаговый параллелизм применяется только для одного субъекта, а не для всех субъектов сразу.
  • В некоторых случаях возвращаемая выполняющимися методами или обратными вызовами задача Task(C#) или CompletableFuture(Java) завершается только после возврата метода. В других случаях асинхронная операция завершается к моменту возврата метода или обратного вызова. В любом случае разблокирование субъектов происходит только после возврата метода или обратного вызова, а также по завершении асинхронной операции.

Повторный вход

Среда выполнения субъектов по умолчанию поддерживает для субъектов повторный вход. Это означает, что, если метод ActorA вызывает метод для ActorB, который вызывает другой метод для ActorA, то этот метод может быть вызван. Все вызовы с таймерами и напоминаниями начинаются с нового логического контекста вызова. Дополнительные сведения см. в статье Повторный вход субъектов Reliable Actors .

Область гарантий параллелизма

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

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

Приступите к работе, создав свою первую службу Reliable Actors: