Я медленно удаляю apache с сервера
Есть у меня серверок (да, да, именно серверок, сервером его назвать сложно). Железо старенькое (2 гига оперативы, AMD Athlon(tm) 64 Processor 3500+, програмный RAID). Админю я его сам, без особых навыков и познаний. Когда-то давным давно (больше года назад) поставил на него Debian 5.0 Lenny (это была вторая в жизни установка linux-системы, до этого ставил только Ubuntu на рабочий ноутбук) и панель управления ISPConfig3 по мануалу. Держу на нем несколько (штук 40) сайтов друзей и клиентов, Redmine, SVN и еще немного по мелочам.
Периодически все это безобразие падает (load average > 20), и приходится на сервере раз в пару часов перегружать apache или высасывать из пальца очередную попытку оптимизации. В общем полный раздрай и разруха. И вот в одну прекрасную субботу я подумал — а почему бы не решить вопрос раз и… И вот в общем.
Под катом — история убитых выходных + предыстория. Интересна в первую очередь мне, чтобы потом легко вспомнить что именно и зачем я ставил. Может быть интересна новичкам в интересном и нелегком (ох, …) деле серверной оптимизации постепенным(!) переводом сайтов из-под Apache c его ModRewrite под Nginx (меня поправили, Сысоев на конференциях не раз говорил, что название сервера стоит читать, как «энжин-икс», спасибо bayandin и DorBer ). Возможно, будет интересна более-менее опытным товарищам, оказавшимся в тех же условиях (Debian Lenny, ISPConfig3, слабое железо, несколько хороших, не сильно хороших и разных сайтов). И более опытным может быть интересно зайти, оставить пару комментариев.
Краткое содержание этой серии:
2. Реверс-прокси и еще один админ (ставим и коряво настраиваем nginx)
3. Наконец-то взялись за ум (nginx + php-fpm + eAccelerator)
Сервер ставился по вот этому мануалу — классический LAMP + Хостинг-панель + phpMyAdmin.
Позже на него поставили Redmine , который пользовали по прямому назначению и SVN. И тот, и другой в качестве web-сервера используют Apache. Один через Passenger , второй через mod_dav_svn. Это важно, потому что Apache после этих установок потяжелел.
Через некоторое время пошла первая волна подвисаний. То ли сайтов стало больше, то ли посещаемость их так сильно выросла, то ли активная разработка (и соответственно активное использование Redmine + SVN) стала тому виной. Но ложился сервак постоянно и всерьез. Нашел среди знакомых вроде более-менее адекватного линуксоида, но толкового ответа от него не добился. (Ну не считать же таковым совет поменять сетевую карту!)
Другой админ провел 3-х дневную инспекцию, посоветовал перевести Apache в режим worker. Ок, сели, рукава засучили, сайты в ISPConfig на FastCGI попереводили (там поле типа select в админке:)), вокруг phpMyAdmin c бубном потанцевали, все .htaccess на предмет директив php_* просмотрели. Админ потерялся. Ну ок, своими силами переставили Apache в worker.
Сервер более-менее нормально (зависая не чаще раза в неделю) работал пару месяцев.
Ссылок на манулы не даю, поскольку шаг действительно лишний.
Оптимизация вторая — welcome to nginx (шаг в правильном направлении)
Опять нашли какого-то админа, но на этот раз схитрили — сначала поговорили, он про MPM и не слышал ничего, читать конфиги апача не умеет, уровень квалификации был признан неудовлетворительным.
Правда, пару раз обмолвился о nginx. Я погуглил, почитал Хабр и решил поставить nginx в качестве реверс-прокси перед Apache. Переезжать полностью на nginx было страшно, почему-то был уверен, что PHP-скрипты будут чуствовать себя неудобно (наверное вспомнился какой-то давний случай, когда правил чужой код на чужом сервере без апача, и там то ли расширений не стояло, то ли сам php старенький был). Вот так вот детские травмы влияют на дальнейшую судьбу серверов.
Итак, ставим nginx на Debian (не забываем, что у нас ISPConfig) вот по этому мануалу . В принципе — все стандартно. Сначала переводим Apache на порт :82 (порт :8080 занят — на нем висит ISPConfig):
После этого меняем порт у всех ранее созданных виртуальных хостов
sed -ie ’s/YOUR-IP:80/YOUR-IP:82/g’ /etc/apache2/sites-available/*.vhost mkdir /root/apache2_vhost_backup/ mv /etc/apache2/sites-available/*.vhoste /root/apache2_vhost_backup/
Осталось не забыть сменить порт для наших приложений (в моем случае это были phpMyAdmin, SVN и Redmine), конфиги которых лежат вне /etc/apache2/sites-available/ (в мануале об этом умалчивают).
Следующий шаг — сделать так, чтобы вновь создаваемые через ISPConfig сайты тоже слушали 82-й порт (в мануале тут ошибочка, если делать как у них — ничего не получится. У меня по крайней мере (ISPConfig 3.0.2) вновь создаваемые сайты слушали 80-й. А комментарий мой на эту тему под статьей я почему-то уже не вижу):
cd /usr/local/ispconfig/server/ cp conf/apache_ispconfig.conf.master conf-custom/ cp conf/vhost.conf.master conf-custom/ #открываем оба исходных файла и меняем порт на :82 vi conf/apache_ispconfig.conf.master conf/vhost.conf.master
Дальше — стандартная установка/настройка libapache2-mod-rpaf (чтобы апач видел IP пользователя) и nginx
Дописываем в конфиг Apache /etc/apache2/apache2.conf 2 строчки
RPAFsethostname On RPAFproxy_ips 127.0.0.1 YOU_IP_ADDRESS
Заменяем default сервер nginx /etc/nginx/sites-available/default вот этим (это старый плохой конфиг, я его специально для статьи сохранил. Я его ниже переделываю. Отличается от мануального тем, что в мануальном все запросы вида www.site.com перенаправляются на site.com, а у меня обрабатываются — просьба/требование сеошников некоторых сайтов. Сходство с мануальным — каждый виртуальный хост можно найти по адресу /var/www/site.com/web/, статику нужно брать именно отсюда):
server { listen 80 default; server_name _; server_name_in_redirect off; resolver 127.0.0.1; #ACHTUNG! так делать не стоит. Смотрите UPD снизу if ($host ~* ^(www\.)(.+)) { set $host2 $2; } if ($host !~* ^(www\.)(.+)) { set $host2 $host; } access_log /var/log/ispconfig/httpd/$host/access.log; location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|swf|flv|mp3)$ { root /var/www/$host2/web; access_log off; expires 30d; } location / { root /var/www/$host2/web; index index.html index.htm index.php; access_log off; proxy_pass http://127.0.0.1:82/; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
Перезапускаем apache и nginx (лучше именно в такой последовательности)
/etc/init.d/apache2 restart /etc/init.d/nginx restart
Все! Прокси стал. Только вот толку от него немного (на моей конфигурации). Ну хорошо, статику отдает теперь nginx. И че? В общем, через пару месяцев сервак опять плачет и жалуется на жизнь. Симптомы те же — раз в 2-3 дня load average > 20, перезапускаем апач — через минуту все нормализуется.
Оптимизация третья — а зачем нам Apache?
Предыстория закончилась. В эту субботу лежу я на диване, читаю интервью и понимаю — время пришло. Поскольку впереди времени немеряно (целые выходные! никому ничего не обещал! ну почти…), решаю даже сделать это правильно — сначала собираем прототип на рабочем ноутбуке (Debian Squeeze), а только потом лезем на живой сервер.
Сказано — сделано. Тушим апач, ставим nginx, переписываем порты у апача, эмулируем в директории /var/www/ перечень доменов (у ISPConfig именно так), забираем с сервера описанный выше конфиг, запускаем оба сервера — профит, прокси готов. Все гуд, тестовый сайт на wordpress бегает.
Ок, если не передавать запросы на Apache — кому тогда? Гугл-гугл, ты могуч… Ага! Отдай запросы FastCGI через wrapper. Супер! так просто! И мануал на русском! Класс! Так, так. Ага, предлагают поставить lighttpd. Ради 1 скрипта? Хм… Ну ладно, ноутбук, не сервер же. Пробуем.
$ sudo aptitude install lighttpd # ок, поставили (кстати, внимательный глаз в процессе установки заметит, что в Squeeze нужный нам скрипт spawn-fcgi идет отдельным пакетом. но от этого только хуже. я его ставил отдельным пакетом, потом сносил, потом опять ставил, но уже весь lighttpd) $ sudo /etc/init.d/lighttpd stop #ок, остановили $ sudo update-rc.d -f lighttpd remove #ок, убрали из автозагрузки $ sudo /usr/bin/spawn-fcgi -a 127.0.0.1 -p 9000 \ -u www-data -g www-data \ -f /usr/bin/php5-cgi \ -P /var/run/fastcgi-php.pid #получаем что-то похожее на ошибку - “child process return 2″ - в общем ничего не стало, никто никого на :9000 не слушает, все плохо. А почему? А все просто в системе нет “/usr/bin/php5-cgi”! $ sudo aptitude install php5-cgi
Все, после установки php5-cgi все сразу станет хорошо — spawn-fcgi запустится, помещенный в /etc/rc.local запустится — в общем все будет хорошо. А нифига! Мануал написан на русском? Жди беды! И точно — на ноутбуке процесс постоянно отваливался, будучи перенесенным на сервер — на тяжелых запросах через два на третий отдавал пустую страницу. Но мы то еще об этом не знаем, nginx на 127.0.0.1:9000 еще ничего не проксирует! Просто не делайте так, я чуть ниже покажу как лучше.
На эту тему написано немеряно. На хабре и снаружи. Из интересного —
ветка форума — хорошо видна эволюция понимания настроек nginx — forum.woweb.ru/topic47631.html
как не надо делать — habrahabr.ru/blogs/nginx/74135/
«достойно всяческого порицания» — vkurseweba.ru/files/nginx-doc.pdf — улыбнула фраза
за вики простите, но все же прочтите — wiki.nginx.org/NginxHttpCoreModule
Итого, у меня получилось 2 файла конфигурации, один для реверс-прокси к Апачу (назвал его proxy):
server { #слушаем 80-й порт, это сервер (в терминах конфига nginx) по-умолчанию listen 80 default; #перечень доменов, которые крутятся на этом сервере server_name mysite.com www.mysite.com; # http://nginx.org/ru/docs/http/ngx_http_core_module.html#server_name_in_redirect server_name_in_redirect off; http://nginx.org/ru/docs/http/ngx_http_core_module.html#resolver resolver 127.0.0.1; #парочка некрасивых if, предназначены для определения пути к директории виртуального хоста #ACHTUNG! так делать не стоит. Смотрите UPD снизу if ($host ~* ^(www\.)(.+)) { set $host2 $2; } if ($host !~* ^(www\.)(.+)) { set $host2 $host; } #надеюсь не нуждается в комментариях access_log /var/log/ispconfig/httpd/$host/access.log; access_log off; #DOCUMENT_ROOT виртуального хоста root /var/www/$host2/web; #извините, не могу прокомментировать что именно делает данная директива index index.html index.htm index.php; #пошли разбираться с полученным урлом. Первым делом проверяем на существование файла. Если файл есть - отдаем его. Если нет - отправляем запрос на index.php в корне домена. (Не волнуйтесь, запросы вида /some-file.php сюда не попадут, они будут сразу обрабатываться соответствующим location) location / { try_files $uri /index.php; } #именно этот location будет обрабатывать запросы вида /some-file.php, и как следствие - на него мы перенаправим запросы на несуществующие файлы из предыдущего location location ~* \.php$ { proxy_pass http://127.0.0.1:82; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
И второй сервер (в терминологии nginx), для работы непосредственно с php (я назвал его default):
server { listen 80; server_name _; server_name_in_redirect off; resolver 127.0.0.1; #ACHTUNG! так делать не стоит. Смотрите UPD снизу if ($host ~* ^(www\.)(.+)) { set $host2 $2; } if ($host !~* ^(www\.)(.+)) { set $host2 $host; } access_log /var/log/ispconfig/httpd/$host/access.log; root /var/www/$host2/web; access_log off; index index.html index.htm index.php; #работает аналогично соответствующей location из первого файла location / { try_files $uri $uri/ @fastcgi; } #именованный location, нормальным образом запросы сюда не попадут, только перенаправленные из других частей конфига. В предыдущем proxy я не создавал такого, поскольку внутри named-location нельзя использовать proxy_pass вида http://127.0.0.1:82 - nginx при перезагрузке ругается, хотя это наверное можно обойти с помощью upstream (смотрите еще ниже). Именно сюда мы переправляем запросы с ЧПУ. Можно было обойтись без него и как в предыдущем примере перенаправлять не на @fastcgi, а на /index.php, но мне почему-то хочется верить, что так будет отрабатывать чуть быстрее. location @fastcgi{ #указываем куда передавать запросы fastcgi_pass 127.0.0.1:9000; #инклюдим файл /etc/nginx/fastcgi_params include fastcgi_params; #задаем скрипт-обработчмк fastcgi_param SCRIPT_FILENAME /var/www/$host2/web/index.php; } #все как в предыдущем примере location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www/$host2/web/$fastcgi_script_name; include fastcgi_params; } }
А теперь самое вкусное. Наличие этих двух серверов включенными (не забываем создавать символические ссылки в папку sites-enabled) у nginx позволяет мне спокойно уйти спать с чуством глубокого внутреннего удовлетворения. Наконец-то я смогу спокойно, один за одним, выбирая самые нагруженные сайты на сервере переводить их на nginx, перепроверять, и в случае проблем за 1 минуту переводить обратно. Можно не самые нагруженные — можно самые массовые. Текущая конфигурация default удовлетворяет правила ModRewrite от Wordpress по умолчанию на 100%. После минимального допиливания — будет удовлетворять еще и джумлу , и Битрикс . А это уже ~80% моего хостинга. К сожалению, ModRewrite для CodeIgniter будет несовместим с этой версией. Но отличаться она будет не сильно. Так что серверов в конфиге nginx будет не 2 — «на Апач» + «на php», а побольше. А разные велосипеды с 48 строками в .htaccess специально на apache оставлю, пусть сволочи помучаются.
Обратите внимание, у первого (proxy) файла стоит listen:80 default; Что это означает? Это означает, что все виртуальные хосты, не указанные в остальных файлах по умолчанию будут отправлены на обработку к Apache. Это-то нам сейчас и нужно. Потом, хочется верить, я перепроверю все сайты и сделаю default сервером по умолчанию (из-за этого и выбрано имя сервера). А на proxy оставлю несколько «счастливчиков».
Вся конфигурация была проверена на ноутбуке и перенесена на сервер без каких-либо неожиданностей. На первый взгляд все работает, крутится, несколько сайтов перевел на nginx, перенастроил default для Joomla, даже Битрикс — и тот завелся!
Конфигурацияплохонькая (к примеру, .htacces…
Источник:
Комментариев нет »
RSS лента комментариев Трэкбэк