Вы здесь

Оптимизация Drupal

Вступление

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

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

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

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

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

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

  • создания тысячи терминов таксономии и привязки их к определённому типу материала,
  • добавления определённому материалу дополнительного поля CCK в котором будет храниться тип продуктов.

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

  • Таксономия позволяет создавать иерархию терминов в словаре, т.е. в словаре с терминами может быть 10 терминов первого уровня, а остальные термины будут потомками одного из этих 10 терминов. Создадим нужную иерархию терминов в словаре.
  • Установим дополнительный модуль — 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.

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

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

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

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

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

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

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

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

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

  • скачаем его;
  • распакуем модуль в папку /sites/all/modules;
  • скопируем файл ajax_authcache.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, e..g, 'localhost:11211')
    'server' => array(),   
    // если используем memcached shared single process 
    'shared' => TRUE,  
    // кэш ключа префикса (для нескольких сайтов)                  
    'prefix' => '', 
    // если используем кеширование на файлах – указываем путь их
    // сохранения              
    'path' => 'files/filecache', 
    // static array cache (advanced) // статический массив кэша (расширенный)
    '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,
  ),
);

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

  • cкачаем модуль  CSS Gzip со страницы — http://drupal.org/project/css_gzip;
  • cкачаем модуль JavaScript Aggregator со страницы — http://drupal.org/project/javascript_aggregator;
  • распакуем модули в папку /sites/all/modules;
  • включим модули на странице: Управление -> Модули (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 файлами, используемыми на сайте.

Оптимизация конфигурации и обслуживания 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 запросов на выдачу страницы браузеру пользователю, производился запрос к базе данных для определения нагрузки на сайт.     

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

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

  • Windows,
  • Lunux,
  • FreeBSD,

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

1. Установим eAccelerator, он является PHP-акселератором, основное назначение которого состоит в кэшировании бинарного представления кода.

Соединимся с сервером по SSH и авторизуемся с правами root. Выполним команды для установки дополнительного пакета php5-dev:

sudo apt-get install php5-dev
sudo apt-get install make

Выполним команды для установки eAccelerator:

sudo cd /tmp/
sudo wget 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

Отредактируем файл 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"

При использовании 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

Создадим кэш каталог для eAccelerator выполнив команды:

sudo mkdir -p /var/cache/eaccelerator
sudo chmod 0777 /var/cache/eaccelerator

Перезапустим Apache:

sudo /etc/init.d/apache2 restart

2. Рекомендуем установить Web-сервер nginx и настроить его работу с Web-сервером Apache так, чтобы страницы отдавал браузеру пользователя Apache, а статический контент (CSS, JavaScript, фото и т.д.) nginx. Либо полностью заменить Web-сервер Apache, Web-сервером nginx.

3. Установим в Apache модуль mod_expires, который позволяет Drupal посылать HTTP-заголовки Expires, кэшируя все статические файлы (изображения, css, javascript и т.п.) в Интернет браузере пользователя на определённый срок или до момента появления новых версий файлов. Настройки взаимодействия Drupal и модуля mod_expires Web-сервера Apache, находится в файле .htaccess в корневой директории сайта:

# Включить mod_expires.
<IfModule mod_expires.c>
 # Разрешить истечение срока.
 ExpiresActive On

 # Кэшировать все файлы на две недели после доступа (A).
 ExpiresDefault A1209600

 # Не кэшировать динамически генерируемые страницы.
 ExpiresByType text/html A1
</IfModule>

4. Для ускорения обработки .htaccess файлов web-сервером их содержание можно перенести в главный файл конфигурации Apache – httpd.conf. После чего необходимо запретить поиск файлов .htaccess в пределах корневого каталога web-сервера, установив AllowOverride в None:

<Directory/>   
 AllowOverride
 …
</Directory>   

В виду того, что некоторые модули внутри своих каталогов могут содержать .htaccess файлы, следует аккуратно работать с данным видом оптимизации, что бы при переносе содержимого всех .htaccess файлов в httpd.conf, не пропустить не один .htaccess файл.

5. Установим на сервере:

  • систему анализа лог файлов (например: AWstats),
  • систему мониторинга производительности сервера (например: Munin);
  • систему для учета сетевого трафика (например: Vnstat).

6. Включим кэш 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

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

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

Заключение

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

Для тестирования скорости работы сайта и оптимизации его контента очень удобно пользоваться плагин YSlow для Интернет браузера Firefox, который показывает подробную статистику по загрузке страниц с вашего сайта.

Обновлённая версия статьи разбитая на главы, доступна на сайте: http://www.mydrupalbook.ru/ .

Автора автора