Notas del Terrible
Заметки Ужасного Зануды

Различие ASP.NET и PHP на IIS

июня 25, 2010 17:43 by terR0Q

Столкнулся с очень увесистым различием в работе ASP.NET и PHP под управлением IIS. Симптом проблемы очень нагляден: на одном и том же сервере .NET-сайты работают быстро, на основе PHP — тормозят.

Такое положение дел достало, начал копать вопрос. Проверка ping’ом показала, что сетевой проблемы нет: ответы приходят максимум за полсекунды (привет, «последняя миля»). Запустил профилирование на сервере и закидал его запросами по всем сайтам. Профиль был короткий, всего 1 минута, но наглядный.

Проблема вкратце: оперативная память была перегружена и её не хватало, активно использовался своп.

Решение: сервер был хиленький, Hyper-V с 512 Мб рамы. Сейчас памяти в 2 раза больше, а процессорного времени в 2,5 раза больше. Теперь занято не 85%, а 71% в среднем, и главное, что не свопятся сайты.

В чём суть проблемы.

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

С PHP история другая. Природа PHP основана на парсинге текста. Как итог, постоянная работа с файловой системой, от которой частично спасает кеширование. Так или иначе, при более менее схожем функциональном объеме, такой сайт будет съедать заметно больше памяти и чаще обращаться к диску, чем сайт под управлением .NET. Именно поэтому сайты на PHP вылетали из оперативной памяти в своп, отсюда и жуткие тормоза в среднем по 2-5 на генерацию ответа — доступ к жесткому диску дорогой.


Ускорение PHP под IIS7

марта 16, 2010 10:56 by terR0Q

Для трёхкратного прироста скорости работы PHP под IIS7 всего-то и надо было, что настроить Zend Optimizer (и подружить с FastCGI) и просто дать полные права к C:\Windows\Temp учетке, от которой работает PHP. А чтобы понять необходимость последнего действа, нужно было просто включить вывод startup-ошибок (display_startup_errors) в PHP и увидеть...

Один важный момент: сначала из дистрибутива потоко-небезопасной версии PHP сделал новую отдельную установку PHP, затем установил Zend Optimizer, указав ему новую инсталляцию PHP; а потом настроил обработку запросов *.php в IIS7, опять же указав на новую инсталляцию PHP. Те же действия, но с изначально установленной в Windows Server 2008 версией PHP не дали результата.


IIS Default Document

ноября 18, 2009 00:30 by terR0Q

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

В настройках веб-узла в списке разделов заходим в Default Document.

Исходный список глуповат: php и aspx файлы в самом низу.

Хотя список и очень маленький, на практике (выделенный виртуальный сервер) подъем нужных дефолтных файлов наверх привел к многократному приросту скорости ответа: какие-то доли секунды от обращения к сайту до начала загрузки против одной или даже нескольких секунд.

Не сравнивал на приложениях asp.net, раньше всегда по инерции выставлял Default.aspx на самый верх, но эффект должен быть тот же, ведь это серверная часть проблемы, а не приложения.

Проверено только под IIS7.

А ведь на IIS7 Default.aspx добавляется автоматом и всегда внизу. Надо проверить на том, что уже есть.


Umbraco debug trace output

октября 27, 2009 16:11 by terR0Q

Ещё одна важная заметка по настройке Umbraco. Движок предусматривает полезную при разработке возможность вывода отладочной информации на странице. Там много всего любопытного, в т.ч. серверные переменные.

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

  1. Открываем файл UrlRewriting.config в каталоге config
  2. Добавляем в rewrites следующие узлы:
    <add name="debugTraceDisable"
    virtualUrl="umbDebugShowTrace" rewriteUrlParameter="IncludeQueryStringForRewrite"
    destinationUrl="~/default.aspx" ignoreCase="true" />
    <add name="debugDisable"
    virtualUrl="umbDebug"
    rewriteUrlParameter="IncludeQueryStringForRewrite"
    destinationUrl="~/default.aspx"
    ignoreCase="true" />

Инфа частично из википедии, как ни странно.

И это весьма хорошо, что разработчики выбрали UrlRewritingNet :)

P.S. Чтобы получить отладочную инфу, надо к УРЛу добавить параметр umbDebugShowTrace=true или umbDebug=true (выдаст расположение макросов).


BlogEngine.NET, Umbraco, IIS7 Integrated

октября 22, 2009 13:37 by terR0Q

И вновь на заметку конфигурационный рецепт, на тему как жить счастливо с BlogEngine.NET, Umbraco и интегрированным режимом работы IIS 7.

Для этого нужно, во-первых, подключить ряд обработчиков и модулей в разделе настроек веб-сервера (узел system.webServer), во-вторых, отключить модули Umbraco. Как итог прописываем следующее содержимое в конфиге BlogEngine:

   1:      <system.webServer>
   2:   
   3:          <security>
   4:              <requestFiltering allowDoubleEscaping='True'/>
   5:          </security>
   6:   
   7:          <modules runAllManagedModulesForAllRequests='true'>
   8:              <add name="WwwSubDomainModule" type="BlogEngine.Core.Web.HttpModules.WwwSubDomainModule, BlogEngine.Core"/>
   9:              <add name="UrlRewrite" type="BlogEngine.Core.Web.HttpModules.UrlRewrite, BlogEngine.Core"/>
  10:              <add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule, BlogEngine.Core"/>
  11:              <add name="ReferrerModule" type="BlogEngine.Core.Web.HttpModules.ReferrerModule, BlogEngine.Core"/>
  12:              <!--Remove the default ASP.NET modules we don"t need-->
  13:              <remove name="PassportAuthentication"/>
  14:              <remove name="Profile"/>
  15:              <remove name="AnonymousIdentification"/>
  16:          </modules>
  17:   
  18:          <handlers>
  19:              <add verb='*' name='File' path='file.axd' type='BlogEngine.Core.Web.HttpHandlers.FileHandler,BlogEngine.Core' />
  20:              <add verb='*' name='Image' path='image.axd' type='BlogEngine.Core.Web.HttpHandlers.ImageHandler,BlogEngine.Core' />
  21:              <add verb='*' name='Syndication' path='syndication.axd' type='BlogEngine.Core.Web.HttpHandlers.SyndicationHandler,BlogEngine.Core' />
  22:              <add verb='*' name='Sitemap' path='sitemap.axd' type='BlogEngine.Core.Web.HttpHandlers.SiteMap,BlogEngine.Core' />
  23:              <add verb='*' name='Trackback' path='trackback.axd' type='BlogEngine.Core.Web.HttpHandlers.TrackbackHandler,BlogEngine.Core' />
  24:              <add verb='*' name='Pingback' path='pingback.axd' type='BlogEngine.Core.Web.HttpHandlers.PingbackHandler,BlogEngine.Core' />
  25:              <add verb='*' name='OpenSearch' path='opensearch.axd' type='BlogEngine.Core.Web.HttpHandlers.OpenSearchHandler,BlogEngine.Core' />
  26:              <add verb='*' name='Metaweblog' path='metaweblog.axd' type='BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler,BlogEngine.Core' />
  27:              <add verb='*' name='RSD' path='rsd.axd' type='BlogEngine.Core.Web.HttpHandlers.RsdHandler,BlogEngine.Core' />
  28:              <add verb='*' name='CSS' path='css.axd' type='BlogEngine.Core.Web.HttpHandlers.CssHandler,BlogEngine.Core' />
  29:              <add verb='*' name='JS' path='js.axd' type='BlogEngine.Core.Web.HttpHandlers.JavaScriptHandler,BlogEngine.Core' />
  30:              <add verb='*' name='Rating' path='rating.axd' type='BlogEngine.Core.Web.HttpHandlers.RatingHandler,BlogEngine.Core' />
  31:              <add verb='*' name='OPML' path='opml.axd' type='BlogEngine.Core.Web.HttpHandlers.OpmlHandler,BlogEngine.Core' />
  32:              <add verb='*' name='BlogML' path='blogml.axd' type='BlogEngine.Core.Web.HttpHandlers.BlogMLExportHandler,BlogEngine.Core' />
  33:              <add verb='*' name='SIOC' path='sioc.axd' type='BlogEngine.Core.Web.HttpHandlers.Sioc,BlogEngine.Core' />
  34:              <add verb='*' name='APML' path='apml.axd' type='BlogEngine.Core.Web.HttpHandlers.Apml,BlogEngine.Core' />
  35:              <add verb='*' name='FOAF' path='foaf*.axd' type='BlogEngine.Core.Web.HttpHandlers.Foaf,BlogEngine.Core' />
  36:          </handlers>
  37:   
  38:          <validation validateIntegratedModeConfiguration='false' />
  39:   
  40:      </system.webServer>

А для отключения наследования веб-настроек Umbraco «обёртываем» узлы system.web, system.web.extensions, applicationSettings и system.webServer узлом location с атрибутом inheritInChildApplications:

<location path="." inheritInChildApplications="false">   

Кстати, приём с location полезен для очень многих случаев. К сожалению, он не работает для configSections.