Сравнение обычного сайта с тяжеловесным и неповоротливым слоном, в отличие от сравнительно легкого и ловкого гепарда, произошло на основе разработки memcached, — технологии, созданной для высоконагруженных проектов вроде LiveJournal и др. Однако часто владельцы обычных сайтов не имеют выделенного сервера, — установка подобного модуля невозможна, — а быстрый сайт все-таки хочется. Посмотрим, что можно сделать в обычных условиях, на типичном платном хостинге (PHP, MySQL)
Сжатие сайта «на лету» (.htaccess)
Главная страница Yahoo, весящая 101 Kb, загружается как 15-килобайтовая. Как?
GZIP-компрессия, отлаженная на стороне сервера (файл .htaccess), позволяет сжимать файлы «на лету». На стороне браузера происходит «распаковка». В результате, сайт открывается в десятки раз быстрее. Несколько строк, которые нужно добавить в .htaccess файл (должен быть включен mod_deflate или mod_gzip – поинтересуйтесь об этом у хостера):
<IfModule mod_deflate.c> # сжимаем text, html, javascript, css, xml: AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript # или, сжимаем файлы по расширению: <Files *.html> SetOutputFilter DEFLATE </Files> # Исключаем старые версии браузеров, не ладящие с компрессией BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html Header append Vary User-Agent env=!dont-vary </IfModule>
Что происходит? Посмотрим поведение браузера и сервера при работе без компрессии:
1. Браузер: Запрашиваю index.html (запрос GET me /index.html)
2. Сервер: Ок, дайте мне взглянуть, есть ли index.html по-близости…
3. Сервер: Нашел его! 100KB. Я посылаю файл. (Код ответа 200)
4. Браузер: Целых 100KB?! Ох… подождите, подождите, идет загрузка… Ок, загружен.
А теперь посмотрим работу браузера и сервера с участием настроек компрессии:
1. Браузер: Эй, могу ли я получить index.html? (запрос GET me /index.html) Или у вас есть сжатая версия?
2. Сервер: Дайте мне найти файл… Да, он здесь. Вы примете сжатую версию?
3. Сервер: Я архивирую найденный index.html (200 OK). Пожалуйста, получите 10 КВ.
4. Браузер: Всего 10КВ? Отлично! Я разархивирую файл и показываю пользователю.
Сжатие сайта «на лету» (php)
Сжатие с помощью PHP осуществляется всего двумя строчками кода в начале и в конце php-скрипта. В начало ключевого скрипта (обычно это index.php для большинства CMS) вносится строка:
<?php ob_start("ob_gzhandler");
— в конец:
ob_flush(); ?>
Проверку, сжимаются ли страницы, можно устроить по адресу: http://www.whatsmyip.org/http_compression/
Форматы для кеширования. Компрессия изображений, flash, видео и музыкальных форматов — не дает никакого эффекта и, по факту, бессмысленна. Обычно для компрессии выделяют так называемую «Большую Тройку»: HTML, Javascript, CSS.
Нагрузка на сервер: Процесс разархивации происходит почти мгновенно, т.к. затрачивает резервы на стороне компьютера пользователя, а не сайта. При архивации (компрессии) на стороне сервера, происходит некоторый расход CPU-ресурсов (нагрузка на сервер), однако, при этом, уменьшается трафик.
Кеширование
Кеширование способно многократно уменьшить нагрузку на сервер и увеличить скорость загрузки страниц сайта. Для кеширования добавляем эти строки в .htaccess файл:
#кешируем html, htm на 12 часов <FilesMatch ".(html|htm)$"> Header set Cache-Control "max-age=43200" </FilesMatch> #кешируем css, javascript и txt-файлов на неделю <FilesMatch ".(js|css|txt)$"> Header set Cache-Control "max-age=604800" </FilesMatch> # кешируем flash и картинок на месяц <FilesMatch ".(flv|swf|ico|gif|jpg|jpeg|png)$"> Header set Cache-Control "max-age=2592000" </FilesMatch> #запрет на кеширование скриптов <FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$"> Header unset Cache-Control </FilesMatch>
Роботы и нагрузка на сервер
Часто основную нагрузку на сервер создают не пользователи, а поисковики. Поисковые роботы могут запрашивать от одной и более страниц в секунду. Такая избыточная нагрузка может приводить к торможению сайта, сообщениям хостера о превышении расхода ресурсов процессора и последующему отключению сайта. Как бороться?
Добавляем следующую запись в файл «robots.txt»:
User-agent: * Crawl-delay: 6
Параметр «Crawl-delay» отвечает за время (в секундах), в которое поисковик будет обращаться за следующей страницей сайта. Для большего эффекта, можно увеличить время с 6-ти до 12-ти секунд. Желательно оградить сайт от излишнего сканирования, запретив определенные каталоги и области сайта, например:
User-agent: * Disallow: /admin/ Disallow: /search
Чтобы оградить сайт от нежелательных роботов, можно прописать в файле .htaccess следующие строки:
SetEnvIfNoCase user-Agent ^FrontPage [NC,OR] SetEnvIfNoCase user-Agent ^Java.* [NC,OR] SetEnvIfNoCase user-Agent ^Microsoft.URL [NC,OR] SetEnvIfNoCase user-Agent ^MSFrontPage [NC,OR] SetEnvIfNoCase user-Agent ^Offline.Explorer [NC,OR] SetEnvIfNoCase user-Agent ^[Ww]eb[Bb]andit [NC,OR] SetEnvIfNoCase user-Agent ^Zeus [NC] <limit get="" post="" head=""> Order Allow,Deny Allow from all Deny from env=bad_bot </limit>
Список User Agent браузеров, роботов и пауков поисковых машин, веб-каталогов, менеджеров закачек, спам-ботов и плохих ботов можно найти на сайте List of User-Agents.
Оптимизация баз данных и php-запросов
Для уменьшения нагрузки на сервер часто бывает необходимым оптимизировать и/или минизировать php-запросы к базам данных.
Для облегчения нагрузки на сервер, первое, что нужно сделать – просмотреть запросы, участвующие на тех или иных (или всех сразу) областях сайта, и избавиться от тех, которые можно перевести в статичный контент.
Большинство CMS используют динамичные скрипты обработки, а так же шаблоны / темы (статичный контент, использующий язык обращения к динамичной обработке). Столкнувшись с проблемой нагрузки на сервер, многие находят выход в том, чтобы ограничить запросы из шаблона, связанные с базами данных. Это могут быть линии в определении кодировки страниц; линии, связанные с версией установленной CMS и др.
Hand-made касается переписания вручную динамичных блоков, часто запрашиваемых на сайте (главное меню, которое редко меняется и, тем не менее, каждый раз обращается к БД; подвал («Footer») и т.д.)
Этот Hand-made, в самом деле, способен сократить нагрузку на сервер и ускорить загрузку страниц.
Излишние запросы к базе данных приводят к нагрузке сервера, а иногда и «засыпанию» (bd_name sleep) баз данных (медленные запросы). Медленные запросы могут встречаться не в регулярных блоках, описанных выше, а в динамичных – например, при постраничном выводе материалов, поиске по сайту.
Есть несколько общих принципов по оптимизации запросов к базе MySQL.
1. Конкретизируйте запрос: вместо «SELECT * from site_users» используйте конкретные поля, которые вам нужны в контексте страницы, например: «SELECT UserID, UserName, FirstName, LastName from site_users». Это актуально, если таблица пользователей (site_users) насчитывает множество полей индивидуальных настроек пользователя. Используйте «SELECT * from site_users» только в случае, если запрос касается одного пользователя, — например, на странице его профиля, — и вам нужно большинство из имеющихся полей (нет смысла перечислять все).
2. Используйте «COUNT» для подсчета. При этом, лучше вести подсчет по ID, чем по всем полям (*): «SELECT COUNT(UserID) from site_users». Вместе с тем, запрос «SELECT COUNT(*)» считается достаточно быстрым при использовании без дополнительных условий (WHERE).
3. Используйте лимит выдачи, если вам нужно ограниченное число для вывода: «SELECT UserID, UserName, FirstName, LastName
from site_users
limit 10».
4. Создание индексов. Если вы используете запросы вида «SELECT UserID, UserName, FirstName, LastName
from site_users
where tab1 = 1 and tab2 = 1
limit 10», нужно проставить индексы соответственно полей tab1 и tab2.
Однако нужно помнить, что излишние индексы на ненужных полях тоже вредны.
Проставление индексов актуально, если вы расширяете функционал CMS и добавляете в таблицах новые поля, по которым проводите выборку.
5. Избегайте усложнения запроса. Не гонитесь за двумя зайцами сразу. Лучше иметь два легких и быстрых запросов, чем один сложный и тормозной. Например, не стоит пытаться в одном запросе выбирать максимальное количество поинтов (MAX) у пользователя из таблицы site_users и количество записей (COUNT) из таблицы users_notes. Такой запрос лучше разделить на два, где в одном будет выбираться MAX, а в другом подсчитываться количество записей.
6. Запросы SELECT, INSERT («выбрать», «вставить») являются наиболее быстрыми по сравнению с UPDATE, DELETE («обновить», «удалить»). Учитывайте это при написании новых скриптов. Также, стоит обратить внимание на использование некоторых «тормозных» ф-ций внутри запроса (например, DISTINCT, RAND и др.).
7. Используйте «GROUP BY» для групповых функций (MIN(), MAX() и др.). Вызов групповых функций для SQL-команд, не содержащих «GROUP BY», эквивалентен выполнению этих функций над всем набором возвращаемых данных. Пример запроса: «SELECT student_name, MIN(test_score), MAX(test_score)
FROM student
GROUP BY student_name;»
Для проверки быстродействия или сравнения двух запросов, используйте оператор EXPLAIN.
Синтаксис:
EXPLAIN имя_таблицы
или EXPLAIN SELECT опции_выборки
Why is it I all the time really feel like you do?