Настройка окружения ASP.NET

111

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

Отключение механизмов трассировки и отладки в ASP.NET

Механизм трассировки ASP.NET Tracing позволяет разработчикам получать диагностическую информацию для той или иной страницы, например, время выполнения и ее путь, состояние сеанса и список HTTP-заголовков.

Хотя механизм трассировки позволяет получать бесценную информацию в процессе разработки и отладки приложений ASP.NET, он оказывает отрицательное влияние на общую производительность приложения, выполняя сбор данных о каждом запросе. То есть, если поддержка трассировки была включена на этапе разработки, отключайте ее перед развертыванием своего приложения в эксплуатационной среде, для чего достаточно просто изменить параметр trace в файле web.config:

<configuration>
	<system.web>
		<trace enabled = "false"/>
	</system.web>
</configuration>

По умолчанию, если явно не указано иное, трассировка отключена (enabled="false"), поэтому, отключить трассировку можно также простым удалением параметра trace из файла web.config.

Когда создается новое веб-приложение на основе ASP.NET, в файл web.config автоматически добавляется конфигурационный раздел system.web --> compilation с атрибутом debug, установленным в значение true:

<configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
    </system.web>
</configuration>

Этот раздел добавляется автоматически в Visual Studio 2012 или 2010. В предыдущих версиях Visual Studio параметру debug по умолчанию присваивается значение false, и когда разработчик впервые попытается отладить приложение, на экран выводится диалог, спрашивающий разрешения изменить значение этого параметра на true.

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

Изменить этот параметр очень просто: достаточно полностью удалить атрибут debug из файла конфигурации или присвоить ему значение false:

<configuration>
    <system.web>
      <compilation debug="false" targetFramework="4.5" />
    </system.web>
</configuration>

Если вы боитесь, что забудете изменить этот параметр при развертывании приложения на действующем сервере, можно заставить все приложения ASP.NET на сервере игнорировать параметр debug, следующий фрагмент в файл machine.config на сервере:

<configuration>
    <system.web>
      <deployment retail="true" />
    </system.web>
</configuration>

Отключение механизма ViewState

Механизм сохранения состояния представления ViewState используется в приложениях ASP.NET Web Forms для сохранения состояния страницы в отображаемую разметку HTML (приложения ASP.NET MVC не используют этот механизм). Механизм ViewState позволяет ASP.NET сохранять состояние страницы для отправки его обратно пользователем. Данные сохраняются в формате HTML, шифруются (по умолчанию шифрование отключено), кодируются в строку Base64 и запоминаются в скрытом поле. Когда пользователь отправляет страницу обратно, содержимое поля декодируется и преобразуется обратно в ассоциативный массив. Многие средства управления сервером используют механизм ViewState для сохранения собственной информации, например, значений своих свойств.

Это очень удобный и очень мощный механизм, но он добавляет в страницу дополнительное содержимое - строку в кодировке Base64, которое может значительно увеличивать объем ответа. Например, страница, содержащая единственный компонент GridView с возможностью постраничного просмотра списка из 800 клиентов, генерирует разметку HTML размером 17 Кбайт, из которых 6 Кбайт приходится на скрытое поле с информацией о состоянии представления, потому что элементы GridView сохраняют свои исходные данные в этом поле. Кроме того, использование поддержки механизма ViewState требует выполнять сериализацию и десериализацию состояния представления для каждого запроса, что влечет дополнительные накладные расходы на обработку страницы.

Увеличение объема страниц при использовании механизма ViewState обычно остается незамеченным для клиентов, обращающихся к веб-серверу в локальной сети. Это объясняется тем, что локальные сети обычно отличаются высокой скоростью передачи и транспортировка очень больших страниц в таких сетях составляет миллисекунды (в оптимально построенной гигабитной локальной сети пропускная способность может достигать ~40-100 Мбайт/сек, в зависимости от используемого аппаратного обеспечения). Однако в более медленных глобальных сетях, таких как Интернет, увеличение размеров страниц становится более заметным.

Если приложению не требуется использовать этот механизм, его лучше отключить. Отключить механизм ViewState можно в файле web.config, для всего приложения целиком:

<configuration>
    <system.web>
      <pages enableViewState="false"></pages>
    </system.web>
</configuration>

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

<%@ Page ... EnableViewState="false" %>

Имеется также возможность отключить поддержку ViewState в отдельных элементах управления:

<asp:ListView ID="ListView1" EnableViewState="false"
	 runat="server" ...>
	 ...
</asp:ListView>

До версии ASP.NET 4 отключение поддержки механизма ViewState в странице делало невозможным ее включение в отдельных элементах управления на странице. Начиная с версии ASP.NET 4 такая возможность была добавлена. Достигается это с помощью свойства ViewStateMode. Например, следующий код отключает поддержку механизма ViewState для всей страницы, кроме элемента управления ListView:

<%@ Page ... EnableViewState="true" ViewStateMode="Disabled" %>

...

<asp:ListView ID="ListView1" ViewStateMode="Enabled"
	 runat="server" ...>
	 ...
</asp:ListView>

Установка атрибута EnableViewState в значение false имеет более высокий приоритет, чем атрибуты ViewStateMode. То есть, если вы предполагаете использовать атрибуты ViewStateMode, обязательно установите атрибут EnableViewState в значение true или просто удалите его (по умолчанию он получает значение true).

Кеш вывода на стороне сервера

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

В продолжение примера с продуктом: чтобы предотвратить выполнение повторных запросов к базе данных всякий раз, когда пользователи запрашивают описание продукта, можно сохранить описание в локальном кеше и обеспечить более быстрое его извлечение, но при этом все еще необходимо генерировать разметку HTML в ответ на каждый запрос. Вместо кеширования исходных данных, ASP.NET предоставляет другую возможность - механизм ASP.NET Output Cache, где сохраняется сама разметка HTML.

Благодаря этому механизму появляется возможность сохранять разметку HTML, которая автоматически будет возвращаться в ответ на последующие запросы, минуя этап выполнения программного кода, генерирующего страницу. Кеш вывода в ASP.NET поддерживается и для приложений на основе Web Forms, где в кеше сохраняются страницы, и для приложений на основе ASP.NET MVC, где сохраняются результаты выполнения операций контроллера.

Например, следующий код использует кеш вывода для сохранения представления, возвращаемого операцией контроллера ASP.NET MVC на срок до 30 секунд:

public class ProductController : Controller
{
        [OutputCache(Duration = 30)]
        public ActionResult Index()
        {
            return View();
        }
}

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

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

public class ProductController : Controller
{
        [OutputCache(Duration = 30, VaryByParam = "id")]
        public ActionResult Index(int id)
        {
            // Извлечь информацию о продукте и настроить
            // соответственно модель
            // ...
            return View();
        }
}

В дополнение к параметрам запроса механизм кеширования вывода может также учитывать HTTP-заголовки запроса, такие как Accept-Encoding и Accept-Language. Например, если метод контроллера может возвращать содержимое на разных языках, в зависимости от HTTP-заголовка Accept-Language, вы можете настроить учет этого заголовка и сохранять в кеше разные версии вывода на разных языках.

Если одни и те же настройки хеширования применяются к разным страницам или операциям, можно создать профиль кеширования и использовать его, вместо повторения настроек снова и снова. Профили кеширования создаются в файле web.config, в разделе system.web --> caching. Например, следующий фрагмент объявляет профиль кеширования, который предполагается использовать вместе с разными страницами:

<configuration>
    <system.web>
      ...
      <caching>
        <outputCacheSettings>
          <outputCacheProfiles>
            <add name="CacheFor30Seconds" duration="30" varyByParam="id"/>
          </outputCacheProfiles>
        </outputCacheSettings>
      </caching>
    </system.web>
</configuration>

Теперь этот профиль можно применить к операции Index:

public class ProductController : Controller
{
        [OutputCache(CacheProfile="CacheFor30Seconds")]
        public ActionResult Index(int id)
        {
            // Извлечь информацию о продукте и настроить
            // соответственно модель
            // ...
            return View();
        }
}

Этот же профиль кеширования можно использовать в веб-форме ASP.NET, указав его в директиве OutputCache:

<%@ OutputCache CacheProfile="CacheFor30Seconds" %>

По умолчанию механизм кеширования вывода в ASP.NET сохраняет информацию в памяти сервера. Однако начиная с версии ASP.NET 4 появилась возможность создать и использовать свой объект-провайдер. Например, можно создать провайдера, который будет сохранять кешированные данные на диске.

Предварительная компиляция приложений ASP.NET

Когда выполняется компиляция проекта веб-приложения ASP.NET, весь код помещается в единственную сборку. Однако веб-страницы (.aspx) и элементы управления (.ascx) не компилируются, и развертываются на сервере в своем исходном виде. При первом запуске веб-приложения (когда поступает первый запрос), ASP.NET динамически компилирует веб-страницы и элементы управления, и помещает скомпилированные файлы в папку ASP.NET Temporary Files. Такая динамическая компиляция увеличивает время ответа на первый запрос, вызывая у пользователя ощущение, что веб-сайт загружается очень медленно.

Чтобы решить эту проблему, можно заранее скомпилировать веб-приложение, включая весь код, страницы и элементы управления, воспользовавшись инструментом компиляции ASP.NET (Aspnet_compiler.exe). Запуск инструмента компиляции на действующем сервере может заметно уменьшить задержку при обработке первого запроса. Для этого необходимо выполнить следующие шаги:

  1. Откройте окно командной строки на сервере.

  2. Перейдите в папку %windir%\Microsoft.NET.

  3. Перейдите в папку Framework или Framework64, в соответствии с настройками пула веб-приложений на поддержку 32-разрядных или 64-разрядных приложений (в 32-разрядных операционных системах существует только папка Framework).

  4. Перейдите в папку, соответствующую версии фреймворка .NET, используемой пулом приложений (v2.0.50727 или v4.0.30319).

  5. Введите следующую команду, чтобы запустить компиляцию (замените WebApplicationName па виртуальный путь к своему приложению):

    Aspnet_compiler.exe -v /WebApplicationName

Тонкая настройка модели процесса в ASP.NET

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

Чтобы предотвратить исчерпание пула потоков выполнения, ASP.NET автоматически корректирует некоторые настройки пула и применяет различные ограничения на количество запросов, которые могут обрабатываться одновременно. Эти настройки находятся в трех основных конфигурационных разделах: system.web --> processModel, system.web --> httpRuntime и system.net --> connectionManagement. Разделы httpRuntime и connectionManagement можно определить в файле web.config приложения. Однако раздел processModel можно определить только в файле machine.config.

Раздел processModel содержит настройки ограничений пула потоков выполнения, такие как минимальное и максимальное количество потоков, а раздел httpRuntime определяет ограничения, имеющие отношение к доступным потокам выполнения, такие как минимальное количество доступных потоков, необходимых для обработки входящих запросов. Раздел connectionManagement определяет максимальное количество исходящих HTTP-соединений на адрес.

Все настройки имеют значения по умолчанию, однако, так как некоторые из них выбраны слишком низкими, ASP.NET включает еще одну настройку, с именем autoConfig, корректирующую некоторые параметры для достижения более оптимальной производительности. Эта настройка, являющаяся частью раздела processModel, поддерживается, начиная с версии ASP.NET 2.0 и автоматически получает значение true.

Параметр autoConfig управляет регулировкой следующих настроек:

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

Следующий фрагмент демонстрирует, как увеличить максимальное количество соединений:

<configuration>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="200" />
    </connectionManagement>
  </system.net>
</configuration>

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

<configuration>
  <system.web>
    <processModel autoConfig="true" minWorkerThreads="10"/>
  </system.web>
</configuration>

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

Пройди тесты
Лучший чат для C# программистов