Оптимізація ASP.NET - практичні поради по роботі з IIS

У даній публікації мова піде про налаштування важливих параметрів пулу ASP.NET-додатків при виклику віддалених веб-сервісів і активної роботи з мережею на стороні сервера через стандартні класи .NET.



Введення
Чи доводилося вам коли-небудь самим налаштовувати виробничі веб-сервера (production servers) під керуванням ОС Windows Server 2008 R2/IIS 7.5 і вище? Для системних адміністраторів, які мають великий досвід роботи з IIS, швидше за все, це тривіальна задача, але для веб-розробників, яким з різних причин іноді доводиться самим брати участь у налаштуванні «бойових» серверів, ця інформація може виявитися дуже корисною.

Отже, приступаємо. Прискорюємо на сайт ASP.NET — економимо гроші підприємства і нерви адміністратора.

Історія
1. Параметри конфігурації IIS
2. Налаштування ASP.NET
3. Рекомендації по оптимізації базової конфігурації
Додатково
Висновок
Посилання

Передісторія
В кінці минулого року в одній великій організації ми зіткнулися з проблемами продуктивності веб-серверів при різко збільшилася користувача навантаженні. У веб-додатку на той момент було зареєстровано понад 200 000 клієнтів. У звичайному режимі одночасно працює близько 1000 користувачів, за день приблизно 10-15% унікальних відвідувачів від загального числа зареєстрованих, тому навантаження відносно невисока. Однак існують пікові навантаження, при яких система виявляється практично непрацездатною.

Веб-администаторы перевірили все, що можна, і ніяк не могли зрозуміти, в чому справа. Адже незважаючи на те, що за всіма основними параметрами системи на фізичному рівні з продуктивністю було все добре, виникали збої з доступністю сервісів, а в пулі збиралася величезна черга запитів. В організації використовується NLB-кластер на 4 вузла (Windows Server 2008 R2 + IIS 7.5 + .NET 4.5), є запас завантаження ПРОЦЕСОРА і пам'яті, мережеві канали великі, кількість використовуваних портів достатня. Всі перевірки вказували на те, що проблеми криються в надрах IIS та налаштування пулу ASP.NET. Живий приклад, коли адміністраторам не завадила б допомога досвідчених веб-розробників…

1. Параметри конфігурації IIS
Загальний опис конфігурації .NETПочинаючи з IIS 7, всі налаштування конфігурації ASP.NET зберігаються в XML-файли (*.config). Вони замінили метабази, яка використовувалася в IIS 6.0 і більш ранніх версіях.

Сміху конфігураційних файлів для IIS 7.x і вище виглядає так:


Рис. 1. Сміху конфігураційних файлів

На вершині ієрархічної конфігурації .NET знаходиться файл machine.config. Він визначає глобальні параметри для конкретної машини. У цьому файлі визначаються підтримувані розділи конфігураційних файлів, що настроюється робочий процес ASP.NET і реєструються постачальники різних модулів. Для оптимізації процесу ініціалізації файл machine.config був значно спрощений, і він розташовується в каталозі:

%systemroot%\Microsoft.NET\Framework\<versionNumber>\CONFIG\

Тут же знаходиться файл machine.config.comments, який дозволяє дізнатися, які параметри використовуються за замовчуванням. З допомогою цих даних у machine.config можна додати параметри з переопределенными значеннями.

Коренем ієрархії конфігурації ASP.NET є файл веб.config, розташований в тому ж каталозі, що і machine.config. Цей файл включає в себе параметри, які використовуються для всіх додатків ASP.NET.

ApplicationHost.config — кореневої файл конфігурації IIS, включає в себе опис усіх сайтів, програм, віртуальних каталогів і пулів додатків, а також глобальні установки за замовчуванням для параметрів веб-сервера. Він знаходиться в таких папках в залежності від версії ОС:
  • для 32-бітної — %WINDIR%\System32\inetsrv\config\
  • для 64-бітної — %WINDIR%\SysWOW64\inetsrv\config\
Кожен локальний файл веб.config застосовує параметри конфігурації для каталогу, в якому він розташований, а також для всіх дочірніх каталогів. Налаштування вкладених каталогів можуть бути перевизначені власними «конфіг».

Перш ніж починати налаштування конфігурації IIS, зверніть увагу на лічильники продуктивності ASP.NET, оцініть поточну і пікове завантаження системи, зафіксуйте наявні показники. Перевірте логи на наявність помилки «HTTP Error 503.2 — Service Unavailable». Постарайтеся визначити, чи не блокується частина запитів у черзі.

Якщо продуктивність системи задовольняє потребам замовника, то краще залишити параметри за замовчуванням, адже вони розраховані для більшості ASP.NET додатків.

При конфігурації IIS можна виділити два основних параметри, що впливають на доступність програми і його продуктивність.

1. Параметр appConcurrentRequestLimit — максимальна кількість одночасних запитів в додатку. Збільшення числа одночасних запитів IIS розширить доступні ресурси веб-сервера для обслуговування запитів. Значення за замовчуванням — 5000.

Найбільш швидко змінити параметр appConcurrentRequestLimit можна утилітою назвою appcmd.exe через командний рядок. Зробити це можна як глобально для всіх сайтів IIS через файл ApplicationHost.config, так і для окремого сайту (додатки).

cd %windir%\system32\inetsrv
appcmd.exe set config /section:system.webserver/serverRuntime /appConcurrentRequestLimit:20000

Виконуємо команду, потім відкриваємо в IIS розділ «Configuration Editor» для кореневого каталогу і перевіряємо нове значення встановленого параметра appConcurrentRequestLimit. Причому тут можна вручну змінити це значення.


Рис. 2. Установка параметра appConcurrentRequestLimit

Для встановлення даного параметра найбільш часто використовується формула:
<usersCount * 1.5>, де usersCount — кількість одночасно працюючих користувачів.

2. Параметр QueueLength — максимальна кількість запитів, які драйвер Http.sys розміщує в черзі пулу додатків. Коли черга заповнена, нові запити отримують помилку «503.2 — Service Unavailable». Значення за замовчуванням — 5000.

Даний параметр можна налаштувати декількома способами:
  • глобально .NET на рівні сервера через machine.config, секція processModel/requestQueueLimit;
  • на рівні IIS через ApplicationHost.config: system.web/httpRuntime -> appRequestQueueLimit;
  • задати значення параметра queueLength для певного пулу.
В якості прикладу змінимо цей параметр для пулу «DefaultAppPool» через командний рядок:

appcmd.exe set apppool "DefaultAppPool" /queueLength:20000

Виконуємо команду, потім відкриваємо в IIS розділ «Application Pools», вибираємо в списку пул «DefaultAppPool », заходимо в меню «Advanced Settings» і перевіряємо.


Рис. 3. Установка параметра queueLength

На замітку: Перегляд поточних запитів в працюючому через пулі «IIS ->Worker Processes»диспетчер IIS виберіть вузол сервера в дереві, потім натисніть на іконку «Worker Processes»:


Рис. 4. Меню Worker Processes диспетчер IIS

У цьому списку ви можете бачити завантаження всіх запущених в даний момент пулів.


Рис. 5. Перегляд працюючих пулів через Worker Processes

При натисканні «Current View Request» з'являється таблиця зі списком адрес оброблюваних сторінок і іншими корисними параметрами. Для оновлення списку можна натискати F5 на екрані. Таким чином, ви зможете знайти «підвисли» запити:


Рис. 6. Список поточних запитів в пулі

Для перегляду показників продуктивності, звичайно, краще використовувати лічильники Performance Monitor, але вони не покажуть вам, як Requests Monitor, URL-адреси поточних запитів.

2. Налаштування ASP.NET
ASP.NET обмежує кількість робочих потоків і потоків портів завершення виклику, що використовуються для виконання запитів. Якщо веб-додаток на стороні сервера активно використовує виклики зовнішніх веб-сервісів, стандартні класи з простору імен System.NET для організації запитів по мережі, то можуть виникнути конфлікти низької продуктивності і взаимоблокировок. Спочатку частина запитів може просто «підвішувати», час виконання буде значно зростати. У гіршому разі, якщо використовується класичний режим налаштування пулу (classic pipeline), це взагалі може призвести до перезавантаження пулу (recycle). Виявлення взаємоблокування ASP.NET не виконується для пулу, запущеного в integrated mode (за замовчуванням у IIS 7 і вище).

Робота пулів програм в інтегрованому режимі має кілька переваг порівняно з роботою в класичному режимі. Рекомендується запускати пули додатків в integrated mode.

На малюнку наочно видно, як відбувається обробка запитів ASP.NET і які параметри мають найбільш важливе значення:


Рис. 7. Процес обробки запитів в ASP.NET

Для оптимальної роботи веб-додатків за замовчуванням включений режим конфігурації налаштувань пулу. В цьому випадку властивість autoConfig одно "true" для секції <processModel> у файлі machine.config, а інші ключові параметри не позначено взагалі.

Добре «розібравшись» в MSDN і файл machine.config.comments, я знайшов опис базової конфігурації пулу. Є 7 основних параметрів, влиящих на роботу ASP.NET з сервісами та мережею:
  • maxConnection
  • maxWorkerThreads / minWorkerThreads
  • maxIoThreads / minIoThreads
  • minFreeThreads
  • minLocalRequestFreeThreads
Параметр maxconnection визначає максимальну кількість одночасних запитів з однієї IP-адреси. При включеній за замовчуванням автоконфігурації пулу цей параметр визначається за формулою:
maxConnection = 12 * cpuNum, cpuNum — це кількість ядер процесора

Таким чином, на сервері з 4-х ядерним процесором максимальна кількість одночасних підключень до кінцевого IP-адресою дорівнює 48=12*4 (за замовчуванням).

Найпростіший спосіб обійти це обмеження — це прямо в коді свого ASP.NET додатки в методі Application_Start у файлі global.asax вказати наступне:

// maximum number of concurrent connections allowed by a ServicePoint object
System.Net.ServicePointManager.DefaultConnectionLimit = Int16.MaxValue;

Більш гнучко налаштовувати maxconnection краще через конфігураційні файли на рівні домену програми (web.config) або веб-сервера (applicationHost.config). Секція <system.net> містить параметри, які визначають, як .NET Framework підключається до мережі.

<system.net>
<connectionManagement>
<add address=".*" maxconnection="5000" />
<add address = "http://www.habrahabr.ua" maxconnection = "9999" /> 
<add address = "http://65.53.32.230:88" maxconnection = "240" />
</connectionManagement>
</system.net>

Увага: Схема для адреси maxconnection повинна бути такою:

http(s)://<IP-адресу або Ім'я сервера>:<Порт>

Збільшення maxconnection дозволяє робити більше одночасних викликів до віддалених сервісів.Цей атрибут не впливає на локальні виклики веб-служб! Необхідно розуміти, що недостатньо тільки обійти обмеження на кількість одночасних підключень до сервісу. Так як збільшення числа одночасних викликів призводить до збільшення використання потоків CLR, які використовуються для створення віддалених і обробки зворотних викликів.

ASP.NET через параметр maxWorkerThreads встановлює обмеження потоків на робочому процесі w3wp.exe (починаючи з IIS 7). У зв'язку з тим, що ASP.NET вбудована в IIS, процеси ASP.NET формують запити на робочих потоках. З-за недостатньої кількості потоків в CLR ThreadPool запити будуть ставати в чергу і «підвішувати».

Аттрібути, задані в секції <processModel>:
1. Параметр maxWorkerThreads — вказує максимальну кількість робочих потоків для кожного процесора в пулі потоків середовища CLR. Значення за замовчуванням — 20. Максимальне значення — 100.

2. Параметр maxIoThreads — вказує максимальну кількість потоків введення/виводу для кожного процесора в пулі потоків середовища CLR. Значення за замовчуванням — 20. Максимальне значення — 100.

3. Параметр minWorkerThreads — вказує мінімальну кількість робочих потоків для кожного процесора, які можуть бути надані негайно для віддаленого обслуговування запиту. Значення за замовчуванням — 1.

4. Параметр minIoThreads — вказує мінімальну кількість потоків введення/виводу для кожного процесора, які можуть бути надані негайно для обробки зворотного виклику. Значення за замовчуванням — 1.

Параметри minWorkerThreads/minIoThreads дозволяють оперативно впоратися з раптово великою кількістю одночасних підключень, коли в разі бездіяльності пул потоків може не мати достатньо часу, щоб досягти оптимального рівня потоків.

Аттрібути, задані в секції <httpRuntime>:
1. Параметр minFreeThreads — визначає кількість потоків, які можуть бути використані для роботи, крім обробки вхідних запитів до робочого процесу. Цей параметр не дає процесу ASP.NET використовувати потоки з пулу для обробки нового HTTP-запиту, якщо загальне число потоків в пулі опуститься нижче цієї межі. Значення за замовчуванням — 8.

2. Параметр minLocalRequestFreeThreads — визначає мінімальну кількість вільних потоків, які ASP.NET тримає доступними для виконання нових локальних запитів. Значення за замовчуванням — 4.

Зверніть увагу, параметри maxWorkerThreads, minWorkerThreads, maxIoThreads, minIoThreads неявно множаться на число процесорів, а параметри minFreeThreads та minLocalRequestFreeThreads — ні.

ASP.NET не буде виконувати більше, ніж наступне кількість одночасних запитів:
(maxWorkerThreads * кількість ЦП) — minFreeThreads

Зверніть увагу: на весь пул програми, тобто на кожен робочий процес w3wp.exe, обслуговуючий пул, є один пул потоків CLR ThreadPool. Для всіх доменів додатків (сайтів), налаштованих на один пул, використовується загальний набір потоків. Отже, для вимогливих до ресурсів додатків краще використовувати окремі пули.

3. Рекомендації по оптимізації базової конфігурації
Насамперед, необхідно точно визначити кількість процесорів на веб-сервері. Як варіант, можна подивитися TaskManager -> вкладка «Performance». Якщо процесор підтримує режим HyperThreadingTechnology (HTT), значить половина ядер логічні (Logical processors), а не фізичні (Cores). Наприклад, при включеному режимі HTT процесор з 4-ма фізичними ядрами буде працювати як 8 логічних ядер:


Рис. 8. Вікно завантаження процесорів в TaskManager

Також можна спробувати скористатися наступними командами в командному рядку:

WMIC CPU Get DeviceID,NumberOfCores,NumberOfLogicalProcessors
або
echo %NUMBER_OF_PROCESSORS%

Наприклад, на сервері з 4-ма процесорами і властивістю autoConfig="true" ASP.NET буде мати наступні параметри за замовчуванням:
maxConnection — 48; maxWorkerThreads — 80; maxIoThreads — 80, minFreeThreads — 8, minLocalRequestFreeThreads — 4.

Якщо веб-сторінка на backend-частини робить кілька мережевих дзвінків для кожного запиту, то MSDN рекомендує використовувати наступні налаштування конфігурації:

  1. maxWorkerThreads = 100 | minWorkerThreads = maxWorkerThreads / 2 = 50
  2. maxIoThreads = 100
  3. maxConnection = 12 * N
  4. minFreeThreads = 88 * N
  5. minLocalRequestFreeThreads = 76 * N, де N — кількість процесорів.
В цьому розділі приведені рекомендації, а не правила. Причому дата публікації цих даних досить давня. Для нашої «бойовий» системи ми використовуємо трохи інші параметри конфігурації. Дані формули — хороша відправна точка для старту оптимізації, вони добре показують залежність параметрів один від одного. Наприклад, збільшивши значення параметра maxConnection в кілька разів, ви легко можете «прикинути» базові значення для інших параметрів.

Зміни в секцію <processModel> може вносити тільки в файлі machine.config з-за встановленого там же атрибута allowDefinition="MachineOnly" при додаванні секції processModel.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\Machine.config:

<section name="processModel" type="System.Web.Configuration.ProcessModelSection, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" allowDefinition="MachineOnly" allowLocation="false" />

Щоб мати можливість встановлювати значення секції processModel для кожного додатка окремо через веб.config, необхідно встановити властивість allowDefinition="Everywhere".

Наведу налаштування конфігурації з нашого веб-сервера
<system.web>
<processModel autoConfig="False" maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50" minIoThreads="8" />
<httpRuntime minFreeThreads="640" minLocalRequestFreeThreads="96">
</system.web>
<system.net>
<connectionManagement>
<add address = "http://Адрес_сервера_1" maxconnection = "5000" />
<add address = "http://Адрес_сервера_2" maxconnection = "5000" /> 
</connectionManagement>
</system.net>

Увага: після внесення змін потрібно оновити Application pools.

Пам'ятайте, що збільшувати дані параметри потрібно тільки в разі необхідності при наявності достатньої кількості ресурсів ЦП.

Для аналізу продуктивності веб-серверів рекомендую налаштувати лічильники ASP.NET через Performance Monitor:

  • ASP.NET Applications\Requests/Sec
  • Web Service\ISAPI Extension Requests/sec
  • ASP.NET\Requests Current
  • ASP.NET\Requests Queued
  • ASP.NET\ Requests Rejected
  • ASP.NET Applications\Requests Executing
  • ASP.NET Applications\Requests Timed Out
  • ASP.NET\ Request Execution Time
Для більш глибокого аналізу процесу w3wp.exe, обслуговуючого пул застосунків IIS, можна спробувати відладчик WinDbg Windows Software Development Kit.

Можливо, що після перевірки лічильників вам доведеться внести корективи у конфігурацію вашої системи.

Додатково
Для кращого розуміння роботи IIS рекомендую ознайомитися, як відбувається процес обробки запиту від браузера користувача до кінцевого пулу застосунків ASP.NET у цій корисній статті «Основи архітектури IIS, або запросопровод для ASP.NET».

Якщо ви використовуєте IIS8 — не буде зайвим звернути увагу на «Повноцінне регулювання навантаження CPU (CPU Throttling)».

Висновок
Для сайтів, які не здійснюють часті мережеві запити на стороні сервера, стандартних налаштувань пулу має вистачати (processModel/autoConfig=«true»). При цьому IIS виставить обмеження в 20 робочих потоків і 12 віддалених з'єднань на ядро. При перевищенні цих значень запити почнуть ставати в чергу і продуктивність веб-додатки впаде.

Якщо ваш сайт працює добре і ви можете оцінити передбачувану навантаження на систему, то не варто нічого міняти. Якщо ж у вас починаються «зависання» при обробці запитів до різних сервісів — не варто звинувачувати в усьому залізо! Краще внести зміни в базову конфігурацію ASP.NET. Майте на увазі, що зміна базових параметрів пулу додатків неодмінно призведе до збільшення завантаження процесора. Оптимальна балансування всіх параметрів системи — ключ до стабільної та продуктивної роботи обладнання. Як кажуть, попереджений — значить озброєний".

Запрошую всіх поділитися вашим досвідом налаштування і оптимізації роботи виробничих веб-серверів на платформі Windows Server.

Посилання

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.