Оптимизируем WordPress по самый не балуй
14 января 2013
Вы, конечно же, в курсе, что этот блог работает на WordPress. Некоторое время назад я начал серьезно беспокоиться относительно быстродействия этого движка. Во-первых, меня волновало количество используемой им памяти. Например, когда по блогу начинают ходить поисковые боты, WordPress запросто может скушать 1 Гб оперативки. Во-вторых, я был обеспокоен временем, за которое у пользователя загружаются страницы. В случае попадания в кэш проблем не возникает, но иначе страница запросто может генерироваться 1-2 секунды.
Для оптимизации блога мною были предприняты следующие шаги.
В первую очередь отключаем все лишние плагины. Если плагин можно заменить куском кода в шаблоне или строкой в файле .htaccess, заменяем. В моем случае остались только следующие девять плагинов — это AddQuicktag, CodeColorer, Disqus, Google XML Sitemaps, Limit Login Attempts, RusToLat, WP-Optimize, WP-PageNavi, WP Super Cache. Строго говоря, от большинства из них также можно избавиться, но, как мы скоро увидим, в этом нет необходимости.
В моем случае предыдущий шаг не дал существенного эффекта. Тогда я попробовал отключить плагин Disqus и использовать вместо него так называемый «универсальный JavaScript код Disqus». Вместо Disqus с тем же успехом можно использовать комментарии ВКонтакта или Facebook’а, тут все зависит от вашей аудитории. В результате страницы стали генерироваться за ~500 мс вместо 1-2 секунд! Я смог удалить все комментарии из БД, что, вероятно, также дало небольшой прирост скорости.
Единственный существенный недостаток перехода с плагина на JavaScript заключается в том, что поисковые системы не будут индексировать комментарии. Однако если вы внимательно посмотрите, по каким запросам на ваш сайт приходят посетители, то скорее всего обнаружите, что к комментариям относятся примерно 0% запросов. По-моему, Миша Шакин когда-то тоже это отмечал.
Дополнение: Как выяснилось, Google прекрасно умеет индексировать комментарии Disqus’а, так что указанного недостатка на самом деле нет!
Раз использование сторонних сервисов дает такой профит, я решил заодно использовать для поиска по сайту Google. Поиск по сайту средствами WordPress, разумеется, при этом следует запретить, например, с помощью правил в .htaccess. Помимо разгрузки хостинга, положительный эффект здесь заключается в том, что Google на самом деле ищет по сайтам на WordPress лучше самого WordPress. В общем случае использование Google плохо тем, что некоторые страницы могут медленно заноситься в индекс. Однако мои посты находятся в индексе Google уже через несколько минут после публикации, так что тут проблемы нет.
Далее. Проверяем, не используется ли в шаблоне десяток CSS или JS файлов, тяжелых картинок и тп. CSS файлы по возможности объединяем и упаковываем, JS прогоняем через Google Closure Compiler (есть приложение и онлайн-версия). Смотрим, нельзя ли уменьшить размер HTML-кода. Например, я заметил, что в заголовках постов у меня используется следующий код:
Я заменил его на:
… сэкономив тем самым посетителям несколько десятков байт трафика. Также размер страниц удалось немного уменьшить с помощью следующего кода в functions.php:
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wp_shortlink_wp_head');
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'feed_links_extra', 3);
Кроме того, этот код уменьшает количество ссылок, по которым пытаются ходить поисковые боты. Затем я принялся за HTTP-заголовки. Из явного мусора (который виден при промохе мимо кэша) в них было обнаружено:
Link: <http://eax.me/?p=8503>; rel=shortlink
X-Pingback выпиливается так:
unset($headers['X-Pingback']);
return $headers;
}
add_filter('wp_headers', 'remove_pingback_header');
А вот код для выпиливания Link:
return NULL;
}
add_filter('get_shortlink', 'empty_shortlink', 10, 4);
Также, чтобы не палить версию PHP (заголовок X-Powered-By), прописываем в файле php.ini:
Кажется, после этого изменения требуется перезапустить Apache. Заодно я проверил список используемых расширений PHP и модулей Apache. В итоге отключил штук 5 ненужных мне модулей/расширений.
Тут до меня дошло, что практически блог отдает только статические страницы. То есть, страницы изменяются, только если я публикую новые посты или редактирую старые. Тогда я зашел в настройки WP Super Cache, где увеличил время жизни кэша и поставил галочку «использовать mod_rewrite». Также я изменил еще пару-тройку вещей, включая правила плагина в .htaccess. К сожалению, точную последовательность действий я уже не воспроизведу. Тут главное не перемудрить — проверьте, что страницы тэгов успешно обновляются при публикации новых постов, что страницы берутся из кэша при просмотре сайта с мобильных устройств и тд. Обратите внимание, что для быстрого прогрева кэша в WP Super Cache есть кнопка «создать общий кэш».
Казалось бы, теперь мы просто отдаем пользователям статику в обход PHP, однако количество используемой памяти что-то не спешило снижаться. Видимо, PHP все-таки что-то делает. Тогда я решил добавить в index.php следующий код:
fwrite($fid,
date("Y-m-d H:i:s")."\t".
$_SERVER['REQUEST_URI']."\t".
$_SERVER['REMOTE_ADDR']."\t".
$_SERVER['HTTP_USER_AGENT']."\n");
fclose($fid);
Оказалось, что по блогу ходит множество ботов, которые ищут дырявые форумы, запрашивают страницы /article-name вместо /article-name/, а также несуществующие файлы с именами вроде apple-touch-icon.png и тд. Все эти запросы шли мимо кэша прямиком в WordPress. Для борьбы с этой проблемой я добавил в .htaccess следующее:
RewriteCond %{REQUEST_URI} ^/[a-z0-9-]+/$ [OR]
RewriteCond %{REQUEST_URI} ^/tag/[a-z0-9-]+/$ [OR]
RewriteCond %{REQUEST_URI} ^/tag/[a-z0-9-]+/feed/$ [OR]
RewriteCond %{REQUEST_URI} ^/tag/[a-z0-9-]+/page/[0-9]+/$ [OR]
RewriteCond %{REQUEST_URI} ^/page/[0-9]+/$
RewriteRule . /index.php [L]
Поскольку некоторые посетители приходят в блог со всяким мусором в query string типа utm_source=
, я также настроил редиректы с URL, содержащих какие-то аргументы в запросе, на те же URL, только без аргументов:
RewriteCond %{REQUEST_URI} !codecolorer
RewriteCond %{QUERY_STRING} !^(p|page_id|preview)=
RewriteCond %{REQUEST_URI} !^/wp-(admin|login|cron|includes)
RewriteRule ^(.*)$ /$1? [R=301,L]
Специально для поисковых роботов Google в robots.txt я дописал:
Disallow: */trackback
Disallow: */comment
Наконец, чтобы посетители, запросившие несуществующую страницу, видели нормальное сообщение об ошибке место «404 Not Found», я завел специальную страницу и прописал в .htaccess:
На данном этапе было совершенно очевидно, что в WordPress не приходит никаких лишних запросов, в большинстве случаев страницы вообще берутся из кэша в обход PHP. За исключением разве что RSS-фидов, ибо WP Super Cache по каким-то причинам не умеет их кэшировать. Следует отметить, что количество используемой памяти на сервере к этому моменту уже существенно снизилось (оно колебалось в районе 100-200 Мб, с редкими пиками до 300-400 Мб), но я все рано не был доволен результатом.
Я зашел на сервер по SSH и обнаружил, что каждый из процессов Apache занимает 17-18 Мб памяти. Значит, одновременно приходит десяток запросов — и вот 200 Мб памяти как ни бывало. Понятно, что за счет copy-on-write это не 200 Мб физической памяти, но при построении графиков в админке хостинга это, похоже, не учитывалось. Тогда я написал хостеру письмо с просьбой поднять Nginx.
Пришлось подождать какое-то время, но результат того стоил:
Уменьшение количества используемой памяти происходит по той причине, что «тяжелый» Apache не занимается передачей данных клиенту, вместо него это делает «легкий» Nginx, поднятый локально. Apache быстро отрабатывает, отдает данные Nginx и завершает работу. Таким образом, одновременно работает меньше процессов Apache и свободной памяти остается больше.
А вот с какой скоростью происходит загрузка страниц:
Скажем так, это не медленнее, чем загружается главная страница Яндекса. И все это на самом обычном шаред хостинге от RU-CENTER. Подозреваю, что переездом на выделенный сервер мне предстоит заниматься очень не скоро.
Помимо описанных выше оптимизаций я также экспериментировал со следующими.
Пробовал перенести картинки и всякие там архивы на Dropbox, но особой экономии памяти или иного выигрыша от этого не увидел и вернул, как было. Пробовал сохранять в кэш gzip’ованные страницы и отдавать их в таком виде посетителям (кстати, это работает даже без mod_gzip). Тоже не увидел профита, к тому же, несжатые страницы все равно приходится класть в кэш на случай, если придет клиент без поддержки gzip. Решил не мудрить и отключить это дело. Пробовал отключать wp-cron в WordPress и прописывать его в crontab. Все сломал и профита не увидел, вернул все взад. Также попробовал плагин WP-Minify, оптимизирующий HTML-код страниц. Прикольная штука, но на время загрузки страниц мало влияет, а вот скорость генерации увеличивает примерно на 100 мс. Выключил и удалил.
Еще нашел прикольный плагин Really Static, позволяющий генерировать статические сайты на WordPress. И потом хоть на narod.ru, хоть на GitHub их заливай. Или, чтоб было удобнее, можно сам WordPress поднять на поддомене с ограничением доступа по паролю, а на основном домене размещать только статику. Стану десятитысясником, обязательно взгляну на него еще раз, а пока от него будет больше неудобств, чем пользы.
Если вам понравилась эта заметка, возможно, вам также будет интересно ознакомиться с моим переводом серии постов Reduce WordPress CPU Usage, некогда опубликованной в блоге cravingtech.com. И еще одно. Не знаю, совпадение или нет, но когда я начал заниматься всеми этими оптимизациями, заметно увеличилось количество переходов с Google.
Итак, вы все еще считаете, что WordPress — тормозной движок? Или все-таки вы не умеете им пользоваться?
Дополнение: Вас также может заинтересовать статья Мой опыт переноса блога с шаред хостинга на VDS.
Метки: PHP, WordPress, Блогинг, Оптимизация, Сайтостроение.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.