Одноранговый сервер состояний ASP.NET - Управление состязанием

ОГЛАВЛЕНИЕ

 Управление состязанием

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

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

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

На схеме выше пользователь заваливает веб-приложение запросами, что, в свою очередь, вызывает передачу запросов сеанса серверу состояний.

Так как все запросы исходят от одного пользователя, все запросы сеанса ссылаются на одинаковый идентификатор сеанса. Балансировщик нагрузки или разделитель состояний распределяет эти запросы между тремя серверами состояний.

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

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

Каждый сервер состояний имеет запросы, ожидающие обработки. Например, если очень востребованный сеанс находится на сервере состояний 3, запросы к данному серверу состояний будут очень быстро обрабатываться поочередно.
Серверы состояний 1 и 2 запускают передачи, запрашивающие передачу сессии. Сообщение в итоге доходит до сервера состояний 3, и запрос передается, например, серверу состояний 2. Запросы к серверу состояний 3, которые не были обработаны, будут ждать до момента завершения передачи.

После завершения передачи сеанса на сервер 2 обрабатываются запросы к серверу 2, в то время как запросы к серверу 3 запускают передачи, запрашивающие сеанс.

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

Еще хуже, если сервер состояний получает сообщение GetTransferMessage после того как он только что передал сеанс, сервер повторно передает сообщение (как объяснено ранее), что вызывает еще больше передач GetTransferMessage по сети, больше передач туда и обратно, и длительную нехватку ресурсов.

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

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

Если поступит много таких запросов, они быстро израсходуют все ресурсы процессора, и сервер остановится.

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

  1. Когда запрос подлежит обработке, и сервер обнаруживает передаваемый сеанс, запрос перестает обрабатываться и ставится в очередь на обработку, когда передача завершится. Это не позволяет запросу пожирать циклы процессора во время ожидания, и освобождает ресурсы, чтобы другие запросы от других пользователей могли быть обработаны. Если число запросов в очереди, ожидающих передачи сеанса, слишком большое, то все эти сообщения отвергаются, так как свидетельствуют о подозрительном сеансе, и сервер не должен утруждаться их обработкой.
  2. После того как передача завершена, и поставленный в очередь запрос готов к повторной обработке, и сервер обнаруживает, что тот же самый сеанс снова передается в другом запросе, то этот запрос будет отвергнут и не станет обрабатываться, так как свидетельствует о крайней сомнительности сеанса.
  3. Перед тем как запрос пытается запросить сеанс из сети (путем широковещания), он проверяет, ждет ли он ответа на предыдущий запрос этого же сеанса, и если да,то запрос ставится в очередь в список запросов, которые будут обработаны, когда запрос будет получен. Это сокращает число сообщений GetTransferMessage, генерируемых в сети, что в свою очередь сокращает ненужные повторные передачи и поиски. Если число запросов в очереди, ожидающих прихода сеанса, слишком большое, то все эти запросы отвергаются, так как служат признаком подозрительного сеанса.
  4. Наконец, все входящие запросы помещаются в очередь с их конкретным идентификатором сеанса, и процессор обработки сообщений циклически опрашивает очереди входящих запросов и обрабатывает их один за другим, как показано ниже:


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