Мысли о приоритетах, размерах очередей сообщений и вообще по следам последних идей...

3 views
Skip to first unread message

Yauheni Akhotnikau

unread,
Mar 29, 2009, 2:32:51 PM3/29/09
to sobje...@googlegroups.com
Доброго дня!

Некоторое время назад мне пришла в голову идея о том, как можно
реализовать контроль за перегрузкой в SObjectizer-4
(http://sourceforge.net/mailarchive/forum.php?thread_name=op.uqolzme5k4pnxe%40eao197nb3.intervale.ru&forum_name=sobjectizer-general).
Я уже обдумал, как ее можно осуществить в седьмой бета версии SObjectizer
4.4.0. Но воплотить в жизнь не успел из-за необходимости отвлечься на
другие проекты. И, наверное, хорошо, что так вышло. Поскольку пару дней
назад я придумал еще одну штуку: задавать ограничения можно не на общий
размер очереди сообщений агента, а на конкретные сообщения.

Например, пусть есть агент, который обрабатывает несколько сообщений:

msg_client_connected, msg_client_disconnected, msg_raw_package (входящие
данные в канале), msg_outgoing_request (сериализация указанного запроса и
отсылка в канал), msg_outgoing_request_state (определение статуса
обработки предыдущего запроса), msg_check_channel_activity (периодическое
сообщение для контроля активности в канале).

Сообщения msg_client_connected, msg_client_disconnected не могут
выбрасываться вообще. Сообщение msg_raw_package так же не может
выбрасываться. (Конечно, обилие входящих пакетов может привести к
перегрузке, но потеря такого сообщения может привести к тому, что данные
из канала будут обрабатываться неправильно).

Сообщения msg_outgoing_request могут выбрасываться, если каждый запрос
самостоятелен (во многих протоколах так и есть, например в SMPP можно
выбрасывать лишние submit_sm, data_sm, а в EMI -- лишние UCP 51
submit_short_message). Еще строже можно поступать с
msg_outgoing_request_status.

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

Все вышесказанное означает, что для такого агента можно и полезно
выставлять ограничения по каждому типу сообщения. Скажем, вот так
(используя идею, описанную здесь:
http://eao197.narod.ru/sobjectizer/rfc/rfc_strict_state_event_checking_and_msg_domains.html):

class a_some_agent_t : public agent_t
{
protected :
message_slot_t< msg_client_connected > slot_msg_client_connected;
message_slot_t< msg_client_disconnected > slot_msg_client_disconnected;
message_slot_t< msg_raw_package > slot_msg_raw_package;
message_slot_t< msg_outgoing_request > slot_msg_outgoing_request;
message_slot_t< msg_outgoing_request_status >
slot_msg_outgoing_request_status;
message_slot_t< msg_check_channel_activity > slot_msg_channel_activity;
...
public :
a_some_agent_t(...)
: base_type_t( ... )
// На сообщения msg_client_connected, msg_client_disconnected
// и msg_raw_package нет ограничений.
, slot_msg_client_connected( so_self() )
, slot_msg_client_disconnected( so_self() )
, slot_msg_raw_package( so_self() )
// На остальные сообщения накладываются ограничения.
// Не более 150 исходящих запросов в обработке.
, slot_msg_outgoing_request( so_self(), 150 )
// Не более 50 запросов статуса.
, slot_msg_outgoing_request_status( so_self(), 50 )
// Проверять состояние канала более одного раза не нужно.
, slot_msg_check_channel_activity( so_self(), 1 )
{...}
};

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

При попытке адаптировать данную идею к SObjectizer-4 я столкнулся со
следующим препятствием: наличие приоритетов у событий. В SObjectizer-4
сообщение может породить несколько событий одного агента. Причем, если это
события одного приоритета, то каждое из них должно обрабатываться в разных
состояниях. Наличие двух и более событий одного приоритета, разрешенных к
обработке в одном состоянии является недопустимой ситуацией. Ведь
SObjectizer не гарантирует порядка вызова таких событий, поэтому система
может вести себя по разному, т.е. система оказывается непредсказуемой.
События с разными приоритетами, порожденные одним сообщением -- это
разрешено и допустимо. Но это так же означает, что сообщение может
генерировать не одну заявку агенту, а несколько. Т.е. контроль за
количеством заявок в очереди сообщений усложняется.

В связи с этим я задумался: а имеют ли смысл вообще события разных
приоритетов для одного агента?

Проанализировав очень немногие случаи использования приоритетов, отличных
от нуля, в наших реальных проектах, я нашел всего две причины, по которым
используется ненулевой приоритет:

1) обеспечение внеочередной реакции на какое-то важное событие. Т.е.
представим себе рабочую нить, на которой работают N агентов. В очереди
заявок этой нити стоит M заявок. Возникает какое-то важное сообщение, для
которого нельзя ждать, пока эти M сообщений обработаются. Такому событию
назначается более высокий приоритет и заявка для него автоматически
помещается в начало очереди.

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

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

Более того, наличие разных приоритетов у событий одного агента может
приводить к интересным ошибкам. Представим себе агента, который
обрабатывает сообщения msg_client_connected с приоритетом 0, а сообщения
msg_client_disconnected с приоритетом 1. Отсылаться сообщения могут в
следующем порядке:

msg_client_connected
msg_client_disconnected
msg_client_connected
msg_client_disconnected

а вот запускаться на обработку события могут в таком порядке:

msg_client_connected
msg_client_disconnected
msg_client_disconnected
msg_client_connected

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

Однако, в случае, когда все события агента имеют один приоритет,
обеспечивается нормальная дисциплина FIFO. И таких фокусов быть не должно.

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

Если использовать в SObjectizer-5 назначение приоритетов именно агентам, а
не событиям, то можно серьезно упростить схему диспетчеризации событий по
сравнению с тем, что есть в SObjectizer-4.

При отсылке сообщения определяются те слоты сообщений, которые связанны с
данным сообщением. Информация о каждом слоте (вместе с ссылкой на
экземпляр сообщения) ставится в очередь рабочей нити (или агента, это уже
зависит от реализации) -- получается заявка. Когда до этой заявки доходит
дело, по слоту и текущему состоянию определяется событие и оно запускается
на обработку. И не нужно будет сложной кухни с event_data_single,
event_data_only_one_of, delivery_man, которая сейчас используется в
SObjectizer-4, и которая привносит изрядные накладные расходы.

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

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

--
Regards,
Yauheni Akhotnikau
Chief Developer
Intervale, http://www.intervale.ru
e-mail:eao...@intervale.ru <mailto:eao...@intervale.ru>

Reply all
Reply to author
Forward
0 new messages