Серверная оптимизация на практике

Недавно ко мне обратился мой постоянный клиент, у которого тормозил сайт http://moybox.ru/

Сайт представляет собой площадку для общения пользователей – тут есть группы, блоги, фотогалереи, короче полноценная социальная сеть, впридачу каждому пользователю создается почтовый ящик с разными крутыми фишками. Но сейчас не об этом. Моей задачей было посмотреть, что можно сделать с сайтом в плане улучшения быстродействия. Как оказалось, даже имея в наличии посредственный сервер с одноядерным процессором Pentium 2800 и 1 гигабайт памяти на борту, можно сделать вполне себе готовый к высоким нагрузкам проект.

Фронтенд – бэкенд

Беглый взгляд обнаружил, что основной функционал сайта составляет InstantCMS. Платформа стандартная LAMP, дистрибутив Ubuntu 10.10. Как это обычно бывает, веб-сервером служил Apache2. Первой идеей стало установка легкого фронтенда nginx перед Apache. Не так давно вышла версия nginx 1.0.0, ее я и поставил на сервер:
wget http://sysoev.ru/nginx/nginx-1.0.0.tar.gz
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 http://127.0.0.1:81/;
}
location ~* \.(jpg|gif|png|css|js)$ {
root /www/site;
}
}

Вот статистика до и после установки nginx, которая поражает (точнее, ужасает скорость Apache в данном случае):
image

Clients 10 20
Delay (min) 0.83 1.6

При использовании nginx:
image

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, сгруппируем файлы главной страницы по размеру:
image
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/*;
}

Вот результат проделанных махинаций, весьма впечатляет:
image
Полный размер главной страницы составил 93.13 KiB, что меньше прежнего размера в 3 раза (!).

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

Еще можно ускорить выполнение php-скриптов за счет кеширования байткода в оперативной памяти. Установим eaccelerator, также из исходников:
wget http://bart.eaccelerator.net/source/0.9.6.1/eaccelerator-0.9.6.1.tar.bz2
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:
image

Вот результат, которого удалось добиться на данном этапе:
image

Clients 10 20 30 40 50
Delay (ms) 410 415 437 416 423

И второй график – время полной загрузки страницы (с учетом всех картинок, скриптов и т.п.):
image

Эта история – хороший пример того, что может происходить, когда в каком-то проекте никто не задумывается о производительности, и оставляет все настройки “по умолчанию”. Как показала практика, даже простая установка nginx как фронтенда к апачу ускоряет сайт в десятки раз.

Похожие статьи

3 thoughts on “Серверная оптимизация на практике”

  1. > gzip bg.jpg > bg.jpg.gz

    На этой строчке стало окончательно понятно, что автор совсем плохо представляет, что именно он делает…
    Вся статья умещается в совет в три слова: “поставьте фронтэндом nginx”.
    Совет разумный, но зачем столько писать?

  2. Это первый шаг, и всегда есть куда стремиться. Но все равно, мне кажется, советы из этой статьи могут кому-то помочь. А может быть, вы покажете какое-нибудь свое творение, нежели оставлять едкие комменты?

Leave a Reply

Your email address will not be published. Required fields are marked *