<p> Недавно мы рассмотрели <a href="http://podlipensky.com/post/2008/10/Quik-Web-Sites-Compress-Optimization-Content.aspx" target="_blank">механизмы оптимизации размера страницы</a>. Следующим нашим объектом оптимизации будет пропускная способность сервера. </p> <blockquote> <p> <strong>Пропускная способность - </strong>скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду. </p> </blockquote> <p> Зачастую, мы ложим статический контент (картинки, javascript, css-код) в тот же самый веб-проект или веб-сайт. Это приводит к тому, что эти ресурсы скачиваются браузером с одного домена. Такой подход может привести к следующим проблемам: </p> <ul> <li>Все ресурсы создают подключения к вашему домену. Поэтому другие, более важные запросы (например запросы к веб-сервису) не могут быть осуществлены, т.к. браузер может создать только два подключения к одному домену. </li> <li>Если вы используете ASP.NET Forms Authentication, то гигансткий Forms Authentication cookie будет посылаться с каждым запросом на ваш домен. Эти cookie будут отправляться при запросе картинки, css-кода или javascript файла, хотя все эти ресурсы, зачастую, не нуждаются в cookie. </li> <li>Такой подход также увеличит размер IIS лога, т.к. он сохраняет cookie для каждого запроса вашего статического контента. Больше того, если вы используете Google Analytics, то к вашим cookie прибавятся еще и четыре больших cookie от компании Google. </li> </ul> <p align="left"> Давайте рассмотрим первую проблему более детально </p> <p align="left"> <a href="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/image_thumb_5.png"><img style="border-width: 0px; display: inline" src="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/image_thumb_thumb.png" border="0" alt="image_thumb" title="image_thumb" width="554" height="252" /></a> </p> <p align="left"> Этот график показывает, что одновременно закачиваются только два файла. Все это происходит только для одного домена. Обратите внимание на загрузку скрипта. Браузер ничего не закачивает параллельно со скриптом. Это объясняется особенностью браузеров в обработке тэга <script>. Таким образом, закачка следующих ресурсов начнется только после завершения закачки и выполнения скрипта. </p> <p align="left"> Но если браузеру удастся открыть еще одно подключение, то закачка той же страницы будет уже выглядеть по-другому </p> <p align="left"> <a href="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/image_thumb_3_2.png"><img style="border-width: 0px; display: inline" src="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/image_thumb_3_thumb.png" border="0" alt="image_thumb_3" title="image_thumb_3" width="548" height="250" /></a> </p> <p> Как видите, время загрузки уменшилось примерно на 40%. Помимо графики, мы можем загружать подобным образом CSS и Javascript-код. </p> <p> Другая проблема, возникающая при загрузке статического контента с того же домена – это огромные Forms Authentication и Google Analytics cookie: </p> <p> <a href="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/podl.png"><img style="border-width: 0px; display: inline" src="/image.axd?picture=WindowsLiveWriter/5e17fab23bd0_8720/podl_thumb.png" border="0" alt="podl" title="podl" width="875" height="295" /></a> </p> <p>   </p> <p>   </p> <p> Таким образом дополнительные 2-3 килобайта будут сопровождать каждый запрос к вашему домену. А оно вам надо? </p> <p> Решить данну проблему можно двумя способами. Первый, и самый неудобный – располагать статический контент в другом домене и сразу ссылаться на него, при разработке проекта. Второй, более приемлемый – написать свой HttpFilter. Этот фильтр будет просматривать содрежимое сраницы, перед отправкой контента пользователю, выявлять href/src атрибуты и прибавляет к ним некий префикс. Скажем если у меня на странице есть следующий код: </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 62px; background-color: #f4f4f4; max-height: 200px"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">img</span> <span style="color: #ff0000">src</span><span style="color: #0000ff">="\images\myphoto.jpg"</span> <span style="color: #ff0000">alt</span><span style="color: #0000ff">="my photo"</span> <span style="color: #0000ff">/></span> </pre> </div> </div> <p> То фильтр может его трансформировать в следующее: </p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 8pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; height: 62px; background-color: #f4f4f4; max-height: 200px"> <div style="border-style: none; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: #f4f4f4"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white"> <span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">img</span> <span style="color: #ff0000">src</span><span style="color: #0000ff">="http://images.podlipensky.com/myphoto.jpg"</span> <span style="color: #ff0000">alt</span><span style="color: #0000ff">="my photo"</span> <span style="color: #0000ff">/></span> </pre> </div> </div> <p> После чего вам необходимо будет создать Url Rewritting модуль (или воспользоваться встроенным в IIS 7), который будет изменять url на свой прежний эквивалент. Для высоконагруженных систем, особенно если они оперируют в основном статическим контентом (например видео- или фото- галлереи) полезно действительно размещать этот контент на других серверах. В этом случае можно еще подключить новую фичу IIS 7 – <a href="http://www.iis.net/downloads/default.aspx?tabid=34&g=6&i=1712" target="_blank">Application Request Routing</a>. Либо воспользоваться <a href="http://en.wikipedia.org/wiki/Content_Delivery_Network" target="_blank">Content Delivery Network</a> сервисом. </p> <p> Впрочем, все вышеописанные методы не новы, и давно используются в коммерческих проектах. Пример подобных оптимизаций, с хорошо описанными исходными кодами, вы сможете найти у <a href="http://msmvps.com/blogs/omar/archive/2008/08/01/loading-static-content-in-asp-net-pages-from-different-domain-for-faster-parallel-download.aspx" target="_blank">Omar AL Zabir’a</a>(который любезно разрешил мне воспользоваться диаграммами, приведенными выше). </p> <p> <strong>Полезные ссылки</strong> </p> <p> <a href="http://www.megaburst.com/caching/smart-caching-for-web-sites-and-blogs/">Smart caching for websites and blogs</a> </p> <p> <a href="http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/" target="_blank">IIS URL Rewriting and ASP.NET routing</a> </p> <a href="http://msmvps.com/blogs/omar/default.aspx" class="headermaintitle">Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5</a>

Недавно мы рассмотрели механизмы оптимизации размера страницы. Следующим нашим объектом оптимизации будет пропускная способность сервера.

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

Зачастую, мы ложим статический контент (картинки, javascript, css-код) в тот же самый веб-проект или веб-сайт. Это приводит к тому, что эти ресурсы скачиваются браузером с одного домена. Такой подход может привести к следующим проблемам:

  • Все ресурсы создают подключения к вашему домену. Поэтому другие, более важные запросы (например запросы к веб-сервису) не могут быть осуществлены, т.к. браузер может создать только два подключения к одному домену.
  • Если вы используете ASP.NET Forms Authentication, то гигансткий Forms Authentication cookie будет посылаться с каждым запросом на ваш домен. Эти cookie будут отправляться при запросе картинки, css-кода или javascript файла, хотя все эти ресурсы, зачастую, не нуждаются в cookie.
  • Такой подход также увеличит размер IIS лога, т.к. он сохраняет cookie для каждого запроса вашего статического контента. Больше того, если вы используете Google Analytics, то к вашим cookie прибавятся еще и четыре больших cookie от компании Google.

Давайте рассмотрим первую проблему более детально

image_thumb

Этот график показывает, что одновременно закачиваются только два файла. Все это происходит только для одного домена. Обратите внимание на загрузку скрипта. Браузер ничего не закачивает параллельно со скриптом. Это объясняется особенностью браузеров в обработке тэга <script>. Таким образом, закачка следующих ресурсов начнется только после завершения закачки и выполнения скрипта.

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

image_thumb_3

Как видите, время загрузки уменшилось примерно на 40%. Помимо графики, мы можем загружать подобным образом CSS и Javascript-код.

Другая проблема, возникающая при загрузке статического контента с того же домена – это огромные Forms Authentication и Google Analytics cookie:

podl

 

 

Таким образом дополнительные 2-3 килобайта будут сопровождать каждый запрос к вашему домену. А оно вам надо?

Решить данну проблему можно двумя способами. Первый, и самый неудобный – располагать статический контент в другом домене и сразу ссылаться на него, при разработке проекта. Второй, более приемлемый – написать свой HttpFilter. Этот фильтр будет просматривать содрежимое сраницы, перед отправкой контента пользователю, выявлять href/src атрибуты и прибавляет к ним некий префикс. Скажем если у меня на странице есть следующий код:

   1: <img src="\images\myphoto.jpg" alt="my photo" />

То фильтр может его трансформировать в следующее:

   1: <img src="http://images.podlipensky.com/myphoto.jpg" alt="my photo" />

После чего вам необходимо будет создать Url Rewritting модуль (или воспользоваться встроенным в IIS 7), который будет изменять url на свой прежний эквивалент. Для высоконагруженных систем, особенно если они оперируют в основном статическим контентом (например видео- или фото- галлереи) полезно действительно размещать этот контент на других серверах. В этом случае можно еще подключить новую фичу IIS 7 – Application Request Routing. Либо воспользоваться Content Delivery Network сервисом.

Впрочем, все вышеописанные методы не новы, и давно используются в коммерческих проектах. Пример подобных оптимизаций, с хорошо описанными исходными кодами, вы сможете найти у Omar AL Zabir’a(который любезно разрешил мне воспользоваться диаграммами, приведенными выше).

Полезные ссылки

Smart caching for websites and blogs

IIS URL Rewriting and ASP.NET routing

Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5