Быстрый способ оптимизации параллельных загрузок на Друпал и nginx

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

Спецификация HTTP 1.1 рекомендует браузерам запрашивать не более двух соединений на хост одновременно. Принята спецификация довольно давно, еще когда деревья были кустарниками, а интернет приходил в дом с телефонного коммутатора, и тогда это имело смысл. Сейчас интернет изрядно потолстел и большинство разработчиков браузеров эту рекомендацию уже давно не соблюдают. Но тем не менее типичные умолчания болтаются где-то в районе 4-х коннектов на хост, а простых пользователей интернета, что способны ускорить его себе, просто увеличив это значение до доступного максимума, я пока не встречал. Так что рекомендации увеличить количество параллельных загрузок, доступных для клиента на серверной стороне, если число объектов веб-страницы превышает десятки штук, уже давно прописались во всех руководствах по оптимизации сайтов. Достигается это довольно простым способом: часть внедряемого контента страниц размещается на других поддоменах вашего сайта и соответственно меняются ссылки в его страницах. Физически эти файлы или скрипты могут располагаться на том же сервере, что и сайт, более того, в той же самой корневой папке.

Сразу коснусь того, что способ оптимизации, использованный мной, рассчитан на частный случай конфигурации доступного мне серверного ПО. Это кэширующий сервер Nginx, основной Apache2 с mod_php и ISP Manager Lite для управления хостингом. Сайт сделан на Drupal 6. Если ваше ПО другое, то добро пожаловать в комментарии для обсуждения.

Идея настройки заключалась в том что, раздавая статический контент - изображения Imagecache, агрегированные CSS и JS файлы, то есть все, что лежит в папке /sites/default/files/, вообще исключить Apache и PHP из процесса, а обойтись для быстроты одним Nginx. Начнём.

Поддомены

Добавляем поддомены в ISP. Я сразу создал 5 штук, чтобы потом уменьшить их число по результатам тестов на быстродействие. Например, такие:
static-0.moisait.ru
static-1.moisait.ru
static-2.moisait.ru
static-3.moisait.ru
static-4.moisait.ru

Если тема вашего сайта нагружена графикой, то сделайте поддомен и для нее, например, theme.moisait.ru.

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

Конфигурация Apache

В файле /etc/apache2/apache2.conf находим секции каждого нашего нового поддомена и делаем их комментариями, дописав # в начале каждой строки. Если их просто удалить, то ISP будет восстанавливать умолчания при последующих изменениях конфигурации. С Apache закончено, он нам больше не нужен.

Конфигурация Nginx

В файле /etc/nginx/nginx.conf тем же способом делаем комментариями все новые секции server, относящиеся к нашим поддоменам и настраиваем свои.

Для каждого поддомена добавляем свою секцию server

  server {
# Слушаем 80 порт на IP-адресе сервера XXX.XXX.XXX.XXX
    listen XXX.XXX.XXX.XXX:80;
# Имя и стандартный алиас поддомена
    server_name static-0.moisait.ru www.static-0.moisait.ru;
# Корневая папка поддомена совпадает с папкой основного
    root /var/www/путь/к/папке/основного/домена/moisait.ru;
# Если запрос браузера берет ресурс из файловой системы Drupal то ищем его там
    location /sites/default/files/ {
# Если файл найден, то отдаем браузеру, иначе передаем на именованный location
      try_files $uri @drupal;
# Разрешаем браузеру кэшировать контент до 2 недель
      expires 14d;
    }
# Именованный location перенаправляет на основной сайт.
# Это позволяет работать Imagecache
    location @drupal {
      rewrite ^(.*)$ http://moisait.ru$1 break;
    }
# Все файлы запрашиваемые не из файловой системы Drupal перенаправляем на основной сайт,
# чтобы исключить дублирование контента на разных доменах
    location / {
      rewrite ^(.*)$ http://moisait.ru$1 break;
    }
  }

Секции server остальных поддоменов настраиваются аналогично, различаясь только цифрой в поддомене

Настройки для поддомена theme.moisait.ru

  server {
    listen XXX.XXX.XXX.XXX:80;
    server_name theme.moisait.ru www.theme.moisait.ru;
    root /var/www/путь/к/папке/основного/домена/moisait.ru;
# Если запрос браузера берет ресурс из папки темы сайта то ищем его там
    location /sites/all/themes/ваша-тема/ {
# Если файл найден, то отдаем браузеру, иначе 404 ошибка
      try_files $uri =404;
      expires 14d;
    }
    location / {
      rewrite ^(.*)$ http://moisait.ru$1 break;
    }
  }

Drupal

Теперь научим Drupal работать с контентом на нескольких поддоменах. Я не стал для этого делать отдельный модуль, а разместил в /sites/default/settings.php функцию custom_url_rewrite_outbound(), которая позволяет переписывать исходящие ссылки. Думаю принцип её работы понятен из кода.

function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
  static $number; # Номер ресурса для статического контента
  if(strpos($path, 'sites/default/files/') === 0) {
    if(!isset($number)) $number = 0;
    $options['absolute'] = TRUE;
    $options['base_url'] = 'http://static-'. ($number % 5) .'.moisait.ru'; // Один из пяти ресурсов
    $number++;
  }
  elseif(strpos($path, 'sites/all/themes/ваша-тема/') === 0) {
    $options['absolute'] = TRUE;
    $options['base_url'] = 'http://theme.moisait.ru';
  }
}

Тестирование

Теперь можно вооружаться тестером скорости загрузки страниц и уменьшая цифру в коде функции <span style="color: #009900;">&#40;</span><span style="color: #000088;">$number</span> <span style="color: #339933;">%</span> <span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span> искать подходящий для вашего сайта оптимум опытным путём. В соответствующей статье советуют 2-3 хоста, но мне кажется, что это очень проектозависимая величина.

Заключение

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

1. Все настройки без изменений, на мой взгляд, подойдут для сервера nginx+php-fast-cgi+drupal

2. Какие будут настройки Apache, если нет Nginx?

3. Я не искал модули для данного функционала, но если они есть, то какие?

4. Есть ли в моем решении подводные камни и как все это с точки зрения безопасности?

5. Есть идея сократить адреса убрав системные пути.

6. Конфигурация автоматического превращения пресетов imagecache в поддомены?

7. Заработает ли это на Drupal 7?

8. Каждая картинка дублируется на нескольких адресах, повлияет ли на SEO?

9. Файлы, генерируемые модулем Advanced CSS/JS aggregation почему-то в данную функцию не попадают.

Welcome to the comments

Источники

Оптимизация параллельных загрузок для минимизации издержек

Nginx: документация

RFC 2068. Hypertext Transfer Protocol -- HTTP/1.1 (8.1.4, стр. 46).

GTmetrix - Analyze Performance of...

Статья и обсуждение на Drupal.RU. Welcome to the comments.

Добавить комментарий

Ограниченный HTML

  • Допустимые HTML-теги: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
CAPTCHA
А не робот ли вы случайно?
3 + 6 =
Решите эту простую математическую задачу и введите результат. Например, для 1+3, введите 4.