вторник, 19 апреля 2011 г.

WebFarm/WebGarden сценарии – управление состоянием, сессией, кешем

Введение

Как известно, стандартная веб страница не хранит состояния. Точнее – каждый раз при отправке запроса назад на сервер на клиент возвращается новая сгенерированная страница. В традиционном веб-программировании каждая последующая оптравка страницы на сервер влечет за собой постоянное сохранение данных формы и восстановление этих значений на клиенте. Для решения этой проблемы в ASP.NET предоставляются множесвтво приемов: ControlState, ViewState, Coockie, Session и т.д. Посмотрим на следующую диаграмму:

States

В данной статье разберем управление состоянием на сервере. Для начала немного погрузимся в глубины IIS.

Что такое AppDomain

AppDomain – это прежде всего термин .NET, а не IIS. Это упрощенный процесс на сервере, использующий для изоляции работающего приложения и играет большую роль в хранении состояний приложения внутри рабочего процесса IIS. Он содержит все InProc содержимое сессии приложения и при завершении данного процесса обнуляется сессия приложения, к которой он прикреплен. На практике, чтобы уловить эту связь с нашим приложением, сделайте следующее: в работающем приложении откройте конфигурационный файла, добавьте пробел вконце и сохраните файл. Все – наш AppDomain сразу же перегружается и очищает все содержимое сессии приложения. Теперь, я думаю, проще представить примерный уровень работы этого процесса.

Роль AppDomain в ASP.NET

Конечно же – эта роль ключевая. Когда сервер IIS получает первый запрос к приложению, создается отдельный Application Domain. Его ключевая задача – обеспечить полную изоляцию от других приложений, работающих на данном сервере, а значит: работать только в рамках выделенных ресурсов, не иметь возможность переходить рамки политики безопасности, абсолютно независимое от других AppDomain загрузк-выгрузки из памяти выделенных ресуросов.

ALC1

В рамках созданного AppDomain для приложения доступны перечисленные способы хранения состояния: InProc Session, Cache, App variables, Static variables. Когда AppDomain завершает свою работу либо перегружается – все эти данные очищаются.

AppDomaincontains

Что такое WebFarm (веб-ферма)

Данная концепция используется в сценариях, когда приложение имеет довольно внушительный поток пользователей и для поддержания качества и приемлемой скорости обработки и передачи данных необходимо использовать множество серверов. Но просто увеличение количества серверов не решает проблему – необходимо также реализовывать механизмы проверки нагруженности определенного сервера для последующей перенаправки запроса на простаивающий сервер. Посему веб-фермы работает в паре с NLB (Network Load Balancer). При каждом запросе сначала определяется наименее загруженный сервер и данный запрос направляется на этот сервер.

webfarm

В данном случае возникает проблема хранения сессийного состояния в AppDomain, так как NLB не гарантирует, что каждый последующий запрос попадет на этот же сервер. В этом случае необходимо использовать OutProc session mode. Более детально дальше.

В некоторых случаях, если невозможно реализовать OutProc session mode NLB можно настроить так, чтобы все запросы с одного IP-адресса всегда приходили на один и тот же сервер. Тем самым мы гарантировано может использовать InProc session mode. Но тут есть и свои неудобства – NLB работает не на полную силу и даже при перегрузке сервера какими-то другими процессами мы все равно вынуждены перенаправлять все запросы с указаного IP на него.

Что такое Web Garden

После того, как новый запрос приходит на сервер, как уже говорилось, для приложения создается AppDomain, в рамках которого работает приложение и в рамках которого доступны все переменные приложения. Каждый AppDomain создается в рамках нового или рабочего ASP.NET процесса w3wp.exe. Согласно настройкам приложения, каждое приложение прикреплено к определенному пулу приложений и создается также в рамках данного пула. Application Pool также налаживает свои ограничения на все процессы внутри него на использование ресурсов, на безопасность и т.д. Так вот, если Application Pool включает в себя несколько рабочих процессов ASP.NET, то такой пул приложеий можно рассматривать как WebGarden. Зачастую преимущества его видны на многопроцессорных серверах, где именно созданием дополнительных процессов загружаем простаивающие процессоры сервера. На рисунку ниже именно первый и второй пул представляют из себя WebGarden.

appDomainsnew

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

Существует два режима хранения сессийный переменныйх:

  • InProc
  • OutProc

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

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

  • StateServer – для хранения данных настраивается дополнительно StateServer. На Windows Server 2003, например, он устанавливается автоматически после установки операционной системы. Необходимо лишь включить (запустить) сервис в настройках.
  • SqlServer – в данном случае выбирается отдельный SqlServer для хранения сессийный переменных. Для правильной конфигурации необходимо выполнить ряд скриптов, которые можно найти на сайте Microsoft. В результате можно восстанавливаеть состояние сессии для пользователя, пришедшего через несколько дней после последнего посещенения ресурса.
  • Собственное решение – имеется возможность создания собственного провайдера управления сессийными перменными, если перечисленные способы не могут быть использованы в вашем варианте, например, если необходимо хранить данные в файлах на сервере.

Управление кешированием при использовании WebFarm\WebGarden

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

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

    filesystemnew

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

    dbdependency

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

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

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

      webserviceapproach
    • Использовать отдельный сервер для кеширования данных и реализовать логику контроля над валидностью данных на этом сервере. Все другие компьютеры фермы через быстрое TCP/IP-соедиение обращаются на этот сервер и получают необходимую порцию данных. Тем самым единожды реализовываются механизмы кеширования и контроля над валидностью кеширования. Сам же кеш-сервер может читать данные из любого другого источника. Остальные веб-сервера имеют доступ только к данному серверу.

      remoting
    • Использование серверов или механизмов сторонних фирм. Например использование CDN от Microsoft или Google для получения статичных данных.