Серверная оптимизация на практике
Сайт представляет собой площадку для общения пользователей – тут есть группы, блоги, фотогалереи, в общем полноценная социальная сеть, впридачу каждому пользователю создается почтовый ящик с разными крутыми фишками. Но сейчас не об этом. Моей задачей было посмотреть, что можно сделать с сайтом в плане улучшения быстродействия. Как оказалось, даже имея в наличии посредственный сервер с одноядерным процессором Pentium 2800 и 1 гигабайт памяти на борту, можно сделать вполне себе готовый к высоким нагрузкам проект.
Фронтенд – бэкенд
Беглый взгляд обнаружил, что основной функционал сайта составляет InstantCMS. Платформа стандартная LAMP, дистрибутив Ubuntu 10.10. Как это обычно бывает, веб-сервером служил Apache2. Первой идеей стало установка легкого фронтенда nginx перед Apache. Не так давно вышла версия nginx 1.0.0, ее я и поставил на сервер:
wget <a class="external" title="Откроется в новом окне - sysoev.ru" target="_blank" href="http://sysoev.ru/nginx/nginx-1.0.0.tar.gz">sysoev.ru/nginx/nginx-1.0.0.tar.gz</a> tar xvzf nginx-1.0.0.tar.gz cd nginx-1.0.0 ./configure --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --with-http_gzip_static_module --with-http_stub_status_module --with-http_realip_module --with-http_ssl_module make install strip /usr/local/nginx/sbin/nginx
Вот часть конфига nginx, описывающая виртуальный хост moybox.ru. В Ubuntu этот файлик кладется в /etc/nginx/sites-enabled.
server {
listen 0.0.0.0:80;
server_name moybox.ru www.moybox.ru;location / {
proxy_pass 127.0.0.1:81/;
}
location ~* \.(jpg|gif|png|css|js)$ {
root /www/site;
}
}
Вот статистика до и после установки nginx, которая поражает (точнее, ужасает скорость Apache в данном случае):
Clients | 10 | 20 |
Delay (min) | 0,83 | 1,6 |
При использовании nginx:
Clients | 10 | 20 | 30 | 40 | 50 |
Delay (ms) | 659 | 686 | 684 | 727 | 819 |
Как видно, Apache еле шевелился даже на небольшом количестве клиентов. Неудивительно, такая у него архитектура. Использование nginx уменьшило среднее время доступа с 1 минуты до 1 секунды, причем уже для 50 клиентов. В случае Apache дело не дошло даже до 30 клиентов.
Отдельные тесты показали, что увеличивать количество рабочих процессов – воркеров nginx (1) и apache (5) не имеет смысла. Средняя скорость доступа практически не меняется вплоть до 50 клиентов, а отдавать бесценную память расплодившимся процессам apache зазря не очень хочется.
gzip_static и оптимизация файлов
С этим разобрались, но естественно, это еще не все пути оптимизации. Теперь посмотрим на размер главной страницы сайта с помощью другого инструмента того же сайта – Page Analyzer, сгруппируем файлы главной страницы по размеру:
Total downloaded data: 290.47 KiB
Видим, что значительную часть занимают CSS, javascript и всякие фоновые картинки. С последним ничего хитрого нет. Травку в нижней части сайта в формате png конвертируем в формат jpeg и получаем 7К из исходных 44К. Изображение письма преобразуем в gif со степенью постеризации 64 и прозрачным фоном, получаем 8К из исходных 16К, практически без потери качества “на глаз”.
Теперь перейдем к оптимизации файлов css/js и собственно html, ведь они одни составляют 130К – около половины веса страницы.
В nginx есть такая замечательная директива gzip, которая позволяет отдавать браузеру сжатую в gzip версию файла. Причем если включена еще и gzip_static, то, к примеру, вместо filename.txt будет отдаваться лежащий рядом заранее заготовленный файл filename.txt.gz. То есть, таким образом экономится время на сжатие файла сервером – один раз сжал и далее его только отдавать. Нужно только следить за актуальностью сжатого файла по отношению к оригиналу.
Наибольший размер имеют styles.css и jquery.js, их и будем оптимизировать. Для их сжатия я использую yui-compressor, вот так (здесь также я решил сжать фоновый файл bg.jpg):
yui-compressor styles.css | gzip -c -5 > styles.css.gz yui-compressor jquery.css | gzip -c -5 > jquery.css.gz gzip bg.jpg > bg.jpg.gz
По многочисленным рекомендациям, ставить уровень сжатия GZIP выше 5 не стоит – только тратится процессорное время, а улучшение сжатия практически незаметно. Другие css- и js-файлы, а также HTML как результат работы InstantCMS, будем сжимать на лету и отдавать по gzip. А мелкие файлы меньше 1 килобайта сжимать вообще не будем.
Вот полученный конфиг nginx:
user www-data;
worker_processes 1;error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
access_log /var/log/nginx/access.log;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
tcp_nodelay on;
gzip on;
gzip_static on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types application/x-javascript text/css;
gzip_min_length 1024;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Вот результат проделанных махинаций, весьма впечатляет:
Полный размер главной страницы составил 93.13 KiB, что меньше прежнего размера в 3 раза (!).
Оптимизация PHP
Еще можно ускорить выполнение php-скриптов за счет кеширования байткода в оперативной памяти. Установим eaccelerator, также из исходников:
wget <a class="external" title="Откроется в новом окне - bart.eaccelerator.net" target="_blank" href="http://bart.eaccelerator.net/source/0.9.6.1/eaccelerator-0.9.6.1.tar.bz2">bart.eaccelerator.net/source/0.9.6.1/eaccelerator-0.9.6.1.tar.bz2</a> tar xvjf eaccelerator-0.9.6.1.tar.bz2 cd eaccelerator-0.9.6.1 apt-get install php5-dev phpize ./configure make install
Прописываем в /etc/php5/apache2/conf.d/eaccelerator.ini следующие параметры:
extension="eaccelerator.so"
eaccelerator.shm_size="64"
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="3600"
eaccelerator.shm_prune_period="1800"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"
Создаем каталог для кеша:
mkdir -m 0777 /var/cache/eaccelerator
и перезапускаем веб-сервер:
/etc/init.d/apache2 restart
Если апач откажется запускаться с вот такой ошибкой:
eAccelerator: Could not allocate 67108864 bytes, the maximum size the kernel allows is 33554432 bytes. Lower the amount of memory request or increase the limit in /proc/sys/kernel/shmmax.
Тогда нужно либо уменьшить запрашиваемый объем памяти с 64 мегабайт на поменьше, либо повысить порог shmmax до требуемого значения:
echo 67108864 > /proc/sys/kernel/shmmax
echo kernel.shmmax = 67108864 >> /etc/sysctl.conf
После этого наши php-скрипты должны кешироваться в памяти, что можно наблюдать, к примеру, в выводе функции phpinfo:
Вот результат, которого удалось добиться на данном этапе:
Clients | 10 | 20 | 30 | 40 | 50 |
Delay (ms) | 410 | 415 | 437 | 416 | 423 |
к – время полной загрузки страницы (с учетом всех картинок, скриптов и т.п.):
Эта история – хороший пример того, что может происходить, когда в каком-то проекте никто не задумывается о производительности, и оставляет все настройки “по умолчанию”. Как показала практика, даже простая установка nginx как фронтенда к апачу ускоряет сайт в десятки раз.