Агенты-близнецы

Author: Евгений Охотников
Contact: eao197 at intervale dot ru; eao197 at yahoo dot com
Version: 0.1
Date: 2007.11.25

Оглавление

Мотивация

Данный текст появился в результате пересечения двух идей:

В текущей версии SObjectizer 4.4.0 многопоточную работу агента можно обеспечить только за счет преобразования его событий в insend-события. Такие события гарантированно вызываются внутри so_4::api::send_msg() на контексте той нити, которая обращается к send_msg(). Это приведет к тому, что если несколько агентов на своих нитях отсылают сообщения ключевому агенту, то события ключевого агента стартуют параллельно на контексте каждого инициатора сообщения.

У решения с insend-событиями есть свои минусы:

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

Суть агентов-близнецов

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

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

Когда агентам-близнецам по их общему имени отсылается сообщение, то возможны следующие результаты:

Управлять способами доставки сообщений агентам-близнецам должен специальный объект-балансировщик. Этот объект реализуется разработчиком агентов-близнецов в соответствии с логикой работы близнецов.

Примеры использования

Маршрутизация mbapi-сообщений

Библиотека MBAPI содержит специального агента-маршрутизатора mbapi-сообщений. Этот агент отвечает за:

  • контроль коммуникационных каналов. Как только создается новый коммуникационный канал агент-маршрутизатор обязан отослать в него информацию о локальных mbox-ах приложения. В ответ из канала приходит информация об mbox-ах удаленной стороны. На основании ответа из канала агент-маршрутизатор модифицирует свою таблицу маршрутизации, добавляя в нее имена удаленных mbox-ов и идентификатор канала. При закрытии какого-либо канала агент-маршрутизатор вычеркивает из таблицы имена ставших недоступными mbox-ов;
  • сериализацию и отправку в коммуникационные каналы mbapi-сообщений. Агент-маршрутизатор получает mbapi-сообщение, определяет, на какой mbox оно адресовано, выбирает канал, через который будет идти доставка, сериализует mbapi-сообщение в обычное сообщение специального глобального агента и отсылает полученное результирующее сообщение в нужный канал.

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

Аналогичная ситуация и с сообщением msg_client_connected с информацией о появлении очередного коммуникационного канала. Его достаточно доставить любому из близнецов, чтобы он отослал в канал список локальных mbox-ов.

Однако, такие сообщения, как msg_client_disconnected (о закрытии коммуникационного канала), список удаленных mbox-ов или сообщение о появлении/исчезновении локального mbox-а, должны доставляться сразу всем агентам-близнецам. Тогда все они смогут поддерживать одинаковые копии таблиц маршрутизации, хотя это и будут собственные копии каждого агента-близнеца.

Распределение криптографических операций по разным контекстам

Если приложение серьезно использует криптографические механизмы, особенно на основе ассиметричной криптографии, то для выполнения ряда криптографических операций может быть выделен специальный агент, в задачи которого может входить:

  • проверка криптографической подписи;
  • формирование криптографической подписи;
  • шифрование и дешифрация данных.

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

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

Некоторые технические подробности

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

При регистрации агентов-близнецов SObjectizer нужно будет передать объект, реализующий следующий интерфейс:

class twin_agents_controller_t
  {
  public :
    //! Создание нужного количества агентов-близнецов.
    /*!
     * Может быть создано любое их количество.
     * Аргумент desired_count задает только оптимальное с
     * точки зрения диспетчера число.
     */
    virtual std::vector< so_4::rt::agent_t * >
    create(
      //! Общее имя для создаваемых агентов.
      const std::string & common_name,
      //! Оптимальное с точки зрения диспетчера число агентов-близнецов.
      unsigned int desired_count ) = 0;

    //! Выбор получателя очередного сообщения.
    /*!
     * Этот метод вызывается при получении сообщения, которое
     * адресуется кому-то из агентов-близнецов.
     *
     * Данный метод отвечает за выбор конкретного агента, который будет
     * обрабатывать данное сообщение. Метод может выбрать любого агента
     * или всех агентов сразу.
     */
    virtual std::vector< so_4::rt::agent_t * >
    select_message_target(
      //! Описание сообщения.
      const message_routing_info_t & message,
      //! Список агентов-близнецов, из которых нужно делать выбор.
      const std::vector< so_4::rt::agent_t * > & twins_list ) = 0;
  };

При этом SObjectizer будет поступать с агентами-близнецами следующим образом.

  1. При регистрации агентов-близнецов SObjectizer использует экземпляр twin_agents_controller_t в качестве фабрики. Метод create() создает экземпляры агентов, которые SObjectizer регистрирует под одним общим именем. Для каждого агента запускается метод so_on_subscription(), отрабатывает evt_start() и т.д. При этом каждый агент-близнец думает, что он единственный агент в системе, имеющий данное общее имя.
  2. При отсылке сообщения на общее имя агентов-близнецов SObjectizer использует экземпляр twin_agents_controller_t для выбора агента-получателя. Для этого вызывается метод select_message_target и сообщение доставляется тем агентам, указатели на которых оказались в возвращенном select_message_target векторе.

Подобный подход обеспечивает прозрачность агентов-близнецов для:

Единственное место, которое знает детали работы агентов-близнецов -- это место создания twin_agents_controller_t и регистрация агентов-близнецов в SObjectizer.

Hosted by uCoz