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

Главные вкладки

Аватар пользователя direqtor direqtor 23 августа 2013 в 18:36

Однажды разглядывая «водопадный» дисплей работы сети в Опере по мере того, как в него грузился один из моих проектов, я понял, что пора и на нем сделать оптимизацию того типа, который указан в заголовке статьи. При довольно быстром в пол-секунды получении кода страницы, полсотни вставленных в нее картинок секунд на пять оттягивали заветное событие 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 [user=drupal]drupal[/user];
# Разрешаем браузеру кэшировать контент до 2 недель
      expires 14d;
    }
# Именованный location перенаправляет на основной сайт.
# Это позволяет работать Imagecache
    location [user=drupal]drupal[/user] {
      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';
  }
}

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

Теперь можно вооружаться тестером скорости загрузки страниц и уменьшая цифру в коде функции <?php($number % 5)?> искать подходящий для вашего сайта оптимум опытным путём. В соответствующей статье советуют 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 comments

Источники

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

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

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

GTmetrix - Analyze Performance of...

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

Комментарии

Аватар пользователя direqtor direqtor 28 августа 2013 в 1:24

Я смотрел этот модуль, но у меня 250 включенных и нужных модулей на этом проекте. Все, что можно сделать не касаясь drupal, делаю не касаясь. Smile
Плюс этого своего решения я вижу в том, что на отдаче контента Drupal, PHP и Apache вообще не участвуют.
И нет ли где хорошей статьи о настройках CDN?

Аватар пользователя VVS VVS 27 августа 2013 в 9:29

3. Модуль CDN - сам пробовал его. Решение очень простое. Модуль решает и 7, 9.

8. Судя по всему в поисковиках надо склеивать поддомены, или редирект 301?

Аватар пользователя Paldru Paldru 27 августа 2013 в 13:58

Я вот для D7 хардкорно запилил замену путей .css .js и .img через file_url_alter(&$uri).
Пока что разбил на 3 поддомена.

К сожалению сайт не на своем сервере поэтому настраивать Nginx я не могу.

Сейчас все файлы переношу вручную, системные пути убраны. Я думаю можно зазюзать функцию - if (file_exists($filename)) в директории else копируем файл на нужный cdn.

Аватар пользователя direqtor direqtor 28 августа 2013 в 1:15

"VVS" wrote:
8. Судя по всему в поисковиках надо склеивать поддомены, или редирект 301?

Последний location 301 редирект и делает для всего, что не лежит в папке files. Но меня другое интересовало. Порядок картинок в страницах может быть разный и одна и та же на одних страницах может браться с поддомена static-0, а на других со static-1 и так далее. Как повлияет это на выдачу изображений в поиске?