Оптимизация работы сайта на Drupal

Разгоняем Drupal

Данный раздел подготовлен при помощи Елены Цаплиной (aka Касихиной) — программиста-разработчика и руководителя нескольких Интернет-проектов: студии дизайна и разработки Интернет-сайтов Aquanther (http://www.aquanther.ru/)), ежедневного женского журнала "Мои подружки" (http://www.moipodruzhki.ru/), программного обеспечения (под управлением ОС Windows) под единым названием — HomAff (сокращение от home affairs).

Елена известна своей публикацией о CMS DrupaL DrupaL ( http://drupaL.ru/node/26290 ), получившей широкое распространение в Рунете.

В данный момент под ее руководством (на базе студии Aquanther) разрабатывается мультимедийный курс по созданию и управлению сайтом с использованием CMS DrupaL. В дальнейшем вместе с мультимедийным курсом планируется распространение модифицированных версий CMS DrupaL, специализированных для определенных типов сайтов, и оказание платной поддержки данной CMS.

1. Вступление

DrupaL — довольная распространенная CMS, и это наложило на нее свой отпечаток: базовая поставка DrupaL является не готовым решением для определенного вида сайта, а фундаментом для его создания. Существуют "сборки" на базе DrupaL, специализированные под определенные виды сайтов, например, под новостные сайты. Но подобные сборки в данный момент мало распространены и плохо поддерживаются. В связи с этим при создании Интернет-сайта на основе стандартной поставки DrupaL используется большое количество готовых дополнительных модулей и тем оформления для DrupaL либо разрабатываются новые модули и темы специально для данного проекта. Последним этапом работ по созданию сайта является его оптимизация, которую условно можно разбить на 4 шага:

  • встроенная оптимизация Drupal;
  • оптимизация Drupal с помощью модулей;
  • оптимизация конфигурации и обслуживания Drupal;
  • оптимизация сервера.

2. Встроенная оптимизация Drupal

  1. Отключим все неиспользуемые модули, так как при генерации страницы перед отправкой ее браузеру пользователя код определенных модулей может выполняться, даже если функционал данного модуля не используется на сайте. На выполнение кода будет тратиться процессорное время сервера, что приведет к более долгой генерации страницы. Пример такого модуля — Statistics. Вместо статистики, выдаваемой данным модулем, можно взять статистику сервиса — GoogLe AnaLytics.

    При создании сайта используем DrupaL версии 6, так как в нем лучше реализованы внутренние средства кэширования. Также в дополнительных модулях (Views, PaneL и т. д.) для DrupaL версии 6 внедрены эффективные методы кэширования. К сожалению не все модули DrupaL версии 5 реализованы для DrupaL версии 6 (например, модуль Sphinx), о чем не следует забывать при планировании разработки Интернет-сайта. Далее будем рассматривать только DrupaL версии 6.

    Хорошо обдумаем варианты использования модулей наподобие CCK (Content Construction Kit) перед реализацией запланированного. Например, простая задача на хранение в базе сайта тысячи типов продуктов, их названий и описаний, решается с помощью: I создания тысячи терминов таксономии и привязки их к определенному типу материала; I добавления определенному материалу дополнительного поля CCK, в котором будет храниться тип продуктов. При усложнении задачи с помощью условия, что все типы продуктов должны быть разбиты на 10 групп, задача решается двумя вариантами. Вариант первый, с использованием таксономии.

  2. Таксономия позволяет создавать иерархию терминов в словаре, т.е. в словаре с терминами может быть 10 терминов первого уровня, а остальные термины будут потомками одного из этих 10 терминов. Создадим нужную иерархию терминов в словаре.
  3. Установим дополнительный модуль — HierarchicaL SeLect (http://drupal.org/project/hierarchical_select ), который позволяет в зависимости от вложенности уровней словаря таксономии отображать определенное количество выпадающих списков. Иначе говоря, пользователю при добавлении новой статьи о продукте на сайт будет выведен один выпадающий список, в котором можно выбрать один из 10 терминов первого уровня (группы типов продуктов). После осуществления выбора будет отображен еще один выпадающий список, в котором будут приведены потомки данного термина в иерархическом дереве терминов данного словаря таксономии (типы продуктов).

    Вариант второй, с использованием CCK.

    • Необходимо определенному материалу добавить 2 дополнительных поля CCK: одно — для хранения групп продуктов, второе — для хранения типов продуктов.
    • Нужно настроить взаимодействие данных полей в зависимости от выбора значений в них.
    • Главные ошибки при решении подобных задач, создающие дополнительную нагрузку на базу данных:
    • создание у определенного материала 10 полей CCK, по полю на каждую группу;
    • при создании у определенного материала поля CCK не указана его длина (поэтому по умолчанию считается, что она максимально возможная).
  4. Используем встроенное кэширование Drupal. Оно позволяет кэшировать информацию, извлеченную из базы данных, а также информацию, полученную при обработке извлеченной информации из PHP.

Кэширование системы меню, фильтров форматов ввода, переменных администрирования (например, название сайта) и настроек модуля производится автоматически. Остальные параметры кэширования можно настроить на странице "Управление — Производительность" ( http://www.exampLe.ru/admin/settings/performance )

На данной странице можно настроить:

  • компрессию страниц;
  • кэширование блоков;
  • оптимизацию CSS-файлов;
  • оптимизацию JavaScript-файлов.

Включим кэширование страниц в режим "нормальный". В данном режиме кэширования страниц при просмотре страницы в первый раз (анонимным, незарегистрированным в системе пользователем) производится сохранение сгенерированной страницы в кэш. В дальнейшем при просмотре данной страницы (анонимным пользователем) она не генерируется заново, а берется из кэша, что значительно ускоряет работу Drupal.

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

Рис. 8.2.

  Настройки производительности для Drupal

Настроим минимальное время жизни кэша страниц для анонимных пользователей. Данный параметр определяет, через какое время после кэширования страницы производится проверка на то, обновлено ли содержимое данной страницы или нет. Если обновлено, то кэш данной страницы очищается. Т.е. если администратор сайта изменил содержимое страницы, он его увидит сразу, а анонимные пользователи — только по прошествии минимального времени жизни кэша.

Включим компрессию страниц для сохранения сжатого кэша страниц и для передачи страницы браузеру пользователя в сжатом виде, если он поддерживает компрессию gzip. Компрессия производится с помощью библиотеки zLib, установленной как расширение в PHP.

Включим кэширование блоков. Принцип работы кэширования блоков аналогичен принципу кэширования страниц. Для супер-пользователя (первого зарегистрированного пользователя при установке DrupaL, его id равен 1) блоки никогда не кэшируются.

Включим оптимизацию CSS- и JavaScript-файлов. Это уменьшит их размер и количество обращений к серверу при загрузке страниц в браузер. Все CSS- и JavaScript-файлы собираются в один (свой файл для CSS (обычно их бывает два: один для отображения на экране, другой — для отображения при печати) и свой — для JavaScript). Таким образом мы уменьшим количество обращений к серверу при загрузке страницы.

3. Оптимизация Drupal с помощью модулей

  1. Установим модуль Authenticated User Page Caching (Authcache), скачать его можно по адресу http://drupaL.org/project/authcache . Данный модуль позволяет кэшировать страницы, как для анонимных пользователей, так и для аутентифицированных ("залогинившихся") пользователей, более качественно, чем встроенное кэширование DrupaL. При установке данного модуля необходимо перенастроить динамический контент на страницах (например, вывод имени аутентифицированного пользователя).

    Authcache сохраняет сжатый кэш страниц отдельно для каждого пользователя или роли. Кэш сохраняется в базе данных или в стороннем средстве кэширования (memcahed, APC, и т. д.). Кэшированные версии страниц для аутентифицированных пользователей (кроме супер-пользователя) передаются с помощью AJAX, поэтому достигается очень быстрое отображение страницы в браузере. Если у аутентифицированного пользователя в браузере отключены JavaScript, то он получает страницы не из кэша. На некоторых серверах скорость загрузки страницы уменьшается до 1 миллисекунды.

    Для установки модуля:

    • скачаем его;
    • распакуем модуль в папку /sites/all/modules;
    • скопируем файл ajaxauthcache.php из папки модуля в корневую директорию сайта (там же находится файл index.php )
    • откроем файл settings.php (в папке /sites/default) и добавим следующий код (без примечаний за // ...) в начало файла после тега <?php:
      $conf['cache_inc'] =
      './sites/all/modules/authcache/api/authcache.inc';
      $conf['authcache'] = array(
        'default' => array(
        // технология кэширования - apc, memcache, db, file,
        // eacc or xcache
        'engine' => 'db',
        // если используем memcached (host:port, например,
        // 'localhost:11211')
        'server' => array(),
        // если используем процесс memcached, shared или single
        'shared' => TRUE,
        // кэш ключа префикса (для нескольких сайтов)
        'prefix' => '',
        // если используем кэширование на файлах — указываем
         // путь их сохранения
        'path' => 'files/filecache',
        // статический массив кэша (расширенный)
        'static' => FALSE,
         ),
      );
                    

    В данном коде устанавливаются настройки модуля Authcache. Указываем, что будем хранить кэш страниц в базе данных ('engine' => 'db'), поэтому все остальные установки не имеют значения, и мы оставляем их без изменений. Более подробно о параметрах данного кода можно прочитать на странице http://drupaL.org/project/cacherouter (на английском языке).

    Включим модуль Authcache на странице "Управление — Модули" ( http://www.exampLe.ru/admin/buiLd/moduLes ). После чего настроим его работу на странице "Управление — Производительность — Authcache" ( http://www.exampLe.ru/admin/settings/performance/authcache ):

    • укажем роли, для которых необходимо кэшировать контент;
    • аннулируем все пользовательские сессии (переключатель — Invalidate all user sessions) при первом запуске;
    • выставим время хранения кэша (в часах);
    • нажмем кнопку "сохранить и очистить кэш" ( Save & clear cached pages) для сохранения изменений.

    Изменим настройки элементов на страницах сайта так, чтобы страница для разных пользователей, принадлежащих одной роли, выглядела одинаково (т. е., например, запретим пользователям управлять видимостью блоков на сайте, если такие блоки существуют).

    В шаблонах тем оформления используем переменные:

    • $user_name - для отображения имени аутентифицированного пользователя;
    • $user_link - для отображения ссылок, связанных с профилем пользователя;
    • $is_page_authcache— если установлен в TRUE, то все хуки данного шаблона темы оформления будут сохранены в кэш.

    Можно также ознакомиться с примером /sites/all/modules/authcache/modules/authcache_example, который показывает, как настроить блоки с пользовательским содержанием (с контентом пользователя).

  2. Если необходимо кэшировать страницы только для анонимных пользователей (без аутентифицированных), можно установить модуль Cache Router. Данный модуль лежит в основе модуля Authcache и кэширует страницы лучше встроенного кэширования Drupal. Скачаем модуль по адресу http://drupal.org/project/authcache . После скачивания распакуем модуль в папку /sites/all/modules. Включим модуль Cache Router на странице "Управление — Модули" (http://www.example.ru/admin/build/modules ). Откроем файл settings.php (в папке /sites/default ) и добавим следующий код в начало файла перед тегом <?php:
    $conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
    $conf['cacherouter'] = array(
      'default' => array(
      'engine' => 'db',
      'server' => array(),
      'shared' => TRUE,
      'prefix' => '',
      'path' => 'sites/default/files/filecache',
      'static' => FALSE,
      'fast_cache' => TRUE,
      ),
     );
              

    После осуществления действий, приведенных выше, страницы создаваемого сайта будут отдаваться сервером браузеру пользователя в сжатом виде, а вот CSS и JavaScript — нет. Исправим это:

    • cкачаем модуль CSS Gzip со страницы http://drupal.org/project/css_gzip ;
    • cкачаем модуль JavaScript Aggregator со страницы http://drupal.org/project/javascript_aggregator ;
    • распакуем модули в папку /sites/all/modules;
    • включим модули на странице ldquo Управление - Модули rdquo ( http://www.example.ru/admin/build/modules );
    • активируем сжатие CSS и JavaScript на странице "Управление - Производительность" ( http://www.example.ru/admin/settings/performance ), отметив чекбоксы "GZip CSS" и "GZip JavaScript" ;
    • внесем изменение в файл .htaccess, расположенный в корневой директории сайта (на основании данных из README.txt, входящего в состав модуля CSS Gzip), пропишем меду тегами <IfModule mod_rewrite.c> и </IfModule> следующий код:
      ### START CSS GZIP ###
      # Requires mod_mime to be enabled.
      <IfModule mod_mime.c="">
        # Send any files ending in .gz with x-gzip encoding
        # in the header.
        AddEncoding x-gzip .gz
      </IfModule>
      # Gzip compressed css files are of the type 'text/css'.
      <FilesMatch "\.css\.gz$">
        ForceType text/css
      </FilesMatch>
      <IfModule mod_rewrite.c="">
        RewriteEngine on
        # Serve gzip compressed css files
        RewriteCond %{HTTP:Accept-encoding} gzip
        RewriteCond %{REQUEST_FILENAME}\.gz -s
        RewriteRule ^(.*)\.css $1\.css\.gz [L,QSA,T=text/css]
      </IfModule>
      ### End CSS GZIP ###
                    
    • сохраним настройки и очистим кэш.

      Если в шаблонах темы оформления необходимо использовать дополнительные CSS и JavaScript, то желательно подключать их с помощью следующих команд:

    • drupal_add_css(‘путь к CSS относительно корневой директории сайта’);
    • drupal_add_js(‘путь к JavaScript относительно корневой директории сайта’);

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

png

4. Оптимизация конфигурации и обслуживания Drupal

От оптимизации Drupal с помощью модулей, перейдем к более сложной оптимизации — оптимизации конфигурации и обслуживания Drupal.

  1. Уменьшим время хранения пользовательских сеансов. Так как DrupaL хранит их в своей базе данных, то сокращение времени их хранения разгрузит базу данных, особенно, если на сайт приходят тысячи пользователей в день. По умолчанию сеансы хранятся 55 часов, уменьшим время их хранения до 24 часов. Для этого на сервере в папке /sites/default в файле settings.php изменим строку
    ini_set('session.gc_maxlifetime', 200000);
            

    на

    ini_set('session.gc_maxlifetime', 86400); // 24 часа (в секундах)
              

    Также в этом файле можно сократить время жизни кэшированных страниц сеансов до 24 часов, изменив строку

    ini_set('session.cache_expire', 200000);
              

    на

    ini_set('session.cache_expire', 1440); // 24 часа (в минутах)
              

    Напоследок в этом же файле изменим время хранения cookie в браузере пользователя, сократив его до 24 часов:

    ini_set('session.cookie_lifetime', 86400); // 24 часа (в секундах)
              

    Если установить время хранения cookie в браузере пользователя равным 0, то cookie будет удаляться сразу после закрытия Интернет-браузера пользователем.

  2. Сократим количество сообщений протоколирования работы сайта, сохраняемых в базе данных. На странице "Управление - Отчеты и сообщения - Отчеты в базе данных" ( http://www.example.ru/admin/settings/logging/dblog ), выставим необходимый максимум отчетов, хранимых в базе данных. Данные отчеты полезны для просмотра попыток взлома сайта, поэтому минимум, который можно выбрать, — это 100 записей. Просмотреть данные отчеты можно, перейдя на страницу "Управление Недавние записи в системном журнале" (http://www.example.ru/admin/reports/dblog ).
  3. Настроим выполнение регулярных процедур (задачи cron), так как при их выполнении очищаются журналы записей сообщений протоколирования работы сайта, устаревшие записи кэша и другие статистические данные. Самым простым способом настройки автоматического запуска регулярных процедур является установка модуля — Poormanscron. Скачаем данный модуль по адресу http://drupal.org/project/poormanscron . Распакуем его в папку /sites/all/modules, активируем модуль на странице "Управление - Модули" (http://www.example.ru/admin/build/modules ). Установим интервал запусков Cron на странице "Управление - Poormanscron" (http://www.example.ru/admin/settings/poormanscron) равным 360 минут (один раз в 6 часов).
  4. В составе Drupal имеется модуль Throttle, который производит оценку количества посетителей сайта и отключает некоторые функцио- нальные возможности, если достигнут порог, установленный администратором. После активации модуля на странице "Управление - Модули" (http://www.example.ru/admin/build/modules) можно увидеть, что у не которых модулей на данной странице кроме флажков включения появились флажки, отмечающие, должен ли данный модуль регулироваться Throttle или нет. Также некоторые блоки могут регулироваться Throttle("Управление -Блоки" (http://www.example.ru/admin/build/block). Настройка Throttle производится на странице "Управление - Регулятор" (http://www.example.ru/admin/settings/throttle), где указывается минимальное количество анонимных посетителей и минимальное количество зарегистрированных пользователей для включения ограничения функционала сайта для них. На этой странице установим вероятностный ограничитель авторегулятора на 20%, чтобы для одного из каждых 5 запросов на выдачу страницы для браузера пользователя производился 1 запрос к базе данных для определения нагрузки на сайт."

5. Оптимизация сервера

Так как сервер сайта может работать под управлением разных операционных систем:

  • Windows
  • Linux
  • FeeBSD

то в каждом случае настройки оптимизации сервера будут отличаться (т. е. установка eAccelerator в Windows и Lunux сильно различается). Ниже приведены только основные рекомендации по оптимизации сервера. Подробно из рекомендаций рассмотрена лишь установка PHP-акселератора на сервер Ubuntu 8.04, так как PHP-акселератор значительно ускоряет работу сайта.

  1. Установим eAccelerator. Он является PHP-акселератором, основное назначение которого состоит в кэшировании бинарного представления кода.
  2. Соединимся с сервером по SSH и авторизуемся с правами root. Выполним команды для установки дополнительного пакета php5-dev:
    sudo apt-get install php5-dev
    sudo apt-get install make
            
  3. Выполним команды для установки eAccelerator:
    sudo cd /tmp/
    sudo wget http://bart.eaccelerator.net/source/0.9.5.3/eaccelerator-
    0.9.5.3.tar.bz2
    sudo tar xvjf eaccelerator-0.9.5.3.tar.bz2
    sudo cd eaccelerator-0.9.5.3
    sudo phpize
    sudo ./configure —enable-eaccelerator=shared
    sudo make
    sudo make install
            
  4. Отредактируем файл php.ini в папке /etc/php5/apache2, вставим в начале файла после тега [PHP] следующий код:
    ; eAccelerator configuration
    ; Note that eAccelerator may also be installed as a PHP extension
    or as a zend_extension
    ; If you are using a thread safe build of PHP you must use
    ; zend_extension_ts instead of zend_extension
    ;extension = "/usr/lib/php5/20060613+lfs/eaccelerator.so"
    zend_extension = "/usr/lib/php5/20060613+lfs/eaccelerator.so"
    eaccelerator.shm_size = "16"
    eaccelerator.cache_dir = "/var/cache/eaccelerator"
    eaccelerator.enable = "1"
    eaccelerator.optimizer = "1"
    eaccelerator.check_mtime = "1"
    eaccelerator.debug = "0"
    eaccelerator.filter = ""
    eaccelerator.shm_max = "0"
    eaccelerator.shm_ttl = "0"
    eaccelerator.shm_prune_period = "0"
    eaccelerator.shm_only = "0"
    eaccelerator.compress = "1"
    eaccelerator.compress_level = "9"
    eaccelerator.allowed_admin_path = "/var/www/eaccelerator"
            
  5. При использовании Zend Optimizer и/или ionCube Loader приведенный выше код будет выглядеть так:
    ; eAccelerator configuration
    ; Note that eAccelerator may also be installed as a PHP extension
    or as a zend_extension
    ; If you are using a thread safe build of PHP you must use
    ; zend_extension_ts instead of zend_extension
    ;extension = "/usr/lib/php5/20060613+lfs/eaccelerator.so"
    zend_extension = "/usr/lib/php5/20060613+lfs/eaccelerator.so"
    eaccelerator.shm_size = "16"
    eaccelerator.cache_dir = "/var/cache/eaccelerator"
    eaccelerator.enable = "1"
    eaccelerator.optimizer = "1"
    eaccelerator.check_mtime = "1"
    eaccelerator.debug = "0"
    eaccelerator.filter = ""
    eaccelerator.shm_max = "0"
    eaccelerator.shm_ttl = "0"
    eaccelerator.shm_prune_period = "0"
    eaccelerator.shm_only = "0"
    eaccelerator.compress = "1"
    eaccelerator.compress_level = "9"
    eaccelerator.allowed_admin_path = "/var/www/eaccelerator"
    ; ionCube Loader configuration
    zend_extension=/usr/local/lib/ioncube/ioncube_loader_lin_5.2.so
    ; Zend Optimizer configuration
    zend_extension=/usr/local/lib/Zend/ZendOptimizer.so
    zend_optimizer.optimization_level=15
            
  6. Создадим кэш-каталог для eAccelerator, выполнив команды
    sudo mkdir -p /var/cache/eaccelerator
    sudo chmod 0777 /var/cache/eaccelerator
            
  7. Перезапустим Apache:
    sudo /etc/init.d/apache2 restart
            
  8. Рекомендуем установить Web-сервер nginx и настроить его работу с веб-сервером Apache так, чтобы страницы он отдавал браузеру пользователя Apache, а статический контент (CSS, JavaScript, фото и т. д.) —nginx. Либо полностью замените веб-сервер Apache веб-сервером nginx.
  9. Установим в Apache модуль mod_expires , который позволяет Drupal посылать HTTP-заголовки Expires , кэшируя все статические файлы (изображения, CSS, JavaScript и т. п.) в Интернет-браузере пользователя на определенный срок или до момента появления новых версий файлов. Настройки взаимодействия Drupal и модуля mod_expires веб-сервера Apache находятся в файле .htaccess в корневой директории сайта:
    # Включить mod_expires.
    <IfModule mod_expires.c="">
      # Разрешить истечение срока.
      ExpiresActive On
      # Кэшировать все файлы на две недели после доступа (A).
      ExpiresDefault A1209600
      # Не кэшировать динамически генерируемые страницы.
      ExpiresByType text/html A1
    </IfModule>
              
  10. Для ускорения обработки .htaccess файлов веб-сервером их содержание можно перенести в главный файл конфигурации Apache — httpd.conf. После чего необходимо запретить поиск файлов .htaccess в пределах корневого каталога веб-сервера, установив AllowOverride в None:
    <Directory/>
    AllowOverride
    …
    </Directory>
            
  11. Ввиду того, что некоторые модули внутри своих каталогов могут соержать файлы .htaccess, следует аккуратно работать с данным видом оптимизации, чтобы при переносе содержимого всех файлов .htaccess в httpd.conf не пропустить не один файл .htaccess.
  12. Установим на сервере:
    • систему анализа лог-файлов (например, AWstats);
    • систему мониторинга производительности сервера (например,Munin);
    • систему для учета сетевого трафика (например, Vnstat).
  13. Включим кэш MySQL и установим его размер равным 64 мегабайтам. Для этого отредактируем файл my.cnf в папке /etc/mysql (при использовании Ubuntu 8.04). Изменим значение
    # query_cache_limit = 1M
    # query_cache_size = 16M

    на

       
    query_cache_limit = 1M
    query_cache_size = 64M
              

    После чего перезапустим MySQL командой

    /etc/init.d/mysql restart
                

    Слишком маленький размер кэша — малоэффективен, а слишком больой размер кэша приводит к тому, что поиск нужной информации в кэше тратит много времени. Поэтому рекомендуем поэкспериментировать с размером кэша на каждом конкретном сервере и подобрать его оптимальный размер.

  14. Проверим: загрузку центрального процессора, нехватку оперативой памяти или места на диске и возможную перегрузку линии связи сервера с Интернетом. Если необходимо разместить базу данных на отдельном сервере, то изменим настройки соединения с базой данных, — они находятся в файле settings.php (в папке /sites/default) — либо разместим сайт на кластере из серверов (например, воспользовавшись услугами сервиса Amazon C2).

6. Заключение

Для просмотра информации о сервере из Drupal существует удобный модуль — System information (http://drupal.org/project/systeminfo ). После его установки и активации информацию о вашем сервере можно посмотреть на странице http://www.example.ru/admin/reports/systeminfo.

Алгоритмы и задачи клиентской оптимизации

Мациевский Н.С. ,  Степанищев Е.В. ,  Кондратенко Г.И.