• Microsoft .NET
  • ASP.NET
  • Стратегии масштабирования для приложений ASP.NET

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

ОГЛАВЛЕНИЕ

 Пояснения реализации

Различные методы программирования применяются для реализации разных аспектов сервера состояний. Некоторые из значительных аспектов освещены ниже.

Платформа

Сервер состояний написан на C# 2.0, но нацелен на каркас NET 3.5, чтобы использовать преимущества класса ReaderWriterLockSlim. Если задан символ NET20, сервер использует вместо этого более медленный класс ReaderWriterLock и может быть нацелен на каркас .NET 2.0.

Протокол

Чтобы создать сервер состояний, способный явно заменить сервер состояний, необходимо получить и понять полную спецификацию протокола связи между веб-сервером и сервером состояний, предоставленным Microsoft. Действия, предпринятые для составления протокола, зафиксированы в обратном хронологическом порядке в http://ahuwanya.net/blog/category/Peer-to-Peer-Session-State-Service.aspx

Передача сообщений

Сервер в основном управляется сообщениями. Подсистема передачи сообщений показана ниже:

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

Если накопленные данные – полное сообщение HTTP, данные отправляются объекту MessageFactory (фабрика сообщений). Объект MessageFactory изучает данные, чтобы определить, какой подходящий экземпляр класса-потомка ServiceMessage (служебное сообщение) нужно создать. Создается экземпляр класса-потомка ServiceMessage, и его реализация метода Process вызывается для обработки сообщения.

Обработка параллельности

Пессимистический механизм параллельности используется во время доступа к состоянию сеанса в словаре сеанса, определенном классом SessionDictionary. Фрагмент состояния сеанса может считываться или изменяться только одним потоком одновременно. Поток объявляет монопольный доступ для производства действий над фрагментом состояния сеанса путем установки свойства IsInUse в истину. Это делается путем вызова метода элементарного сравнения  и перестановки CompareExchangeInUse (обертка метода .NET Interlocked.CompareExchange, производящего действия над свойством IsInUse). Установка данного свойства в истину извещает остальные потоки, что другой поток работает с указанным состоянием сеанса.

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

Таймеры – или их отсутствие

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

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

Диагностика

Класс Diags применяется для слежения за сообщениями, записи действий сервера и обнаружения взаимоблокировок. Методы в классе Diags условные и не будут компилироваться в коде конфигурации выпуска.  Символ VERBOSE (словесный) может быть задан для просмотра или записи всех действий, происходящих на сервере. Это особенно полезно для консольного сервера, выводящего свои данные в консольное окно. Если символ VERBOSE не задан, отображается только важная информация или неожиданные ошибки.

Защита

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

Например, рассмотрим конфигурацию веб-сервер – сервер состояний Microsoft, показанную ниже.

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

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

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

Топологии сети

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

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

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

Сеть C - сеть типа "звезда". Преимущество обладания сетью типа “звезда” в том, что независимо от количества новых узлов, добавленных в кольцевую сеть, сообщение доходит до любого узла в сети всего за два перехода (прыжка).
Сеть D – сеть из трех звездообразных сетей, образующая большую звездообразную сеть. Сообщение проходит через такую сеть также за меньшее число переходов. Обе сети страдают от недостатка: если центральный узел ломается, вся сеть ломается.

Путем соединения краевых узлов в сети D, в  сети E формируется частичная ячеистая сеть. Сеть E – продуманная комбинация кольцевой сети и звездообразной сети. Если центральный узел ломается, сеть продолжает функционировать, и сообщение проходит через сеть за меньшее число переходов, чем через кольцевую сеть.

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

Интересные сценарии

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

Передачи при отключении

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

Повторные передачи

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

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

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

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

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

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