Как стать автором
Обновить

Debian и LiveStreet. Опыт оптимизации сайта на LiveStreet

Приветствую все хабрасообщество! Эта статья, в основном, посвящена людям, которые работают с прекрасной CMS LiveStreet. И т.к. я еще только учусь администрированию веб-серверов, я готов выслушать все замечания моих конфигов. Я устойчив к конструктивной критике, и все ошибки запоминаю и стараюсь не допускать их в будущем.

Сегодня я хочу описать вам свой опыт, который я получил при оптимизации своей слабенькой VDS. Начну с небольшой предыстории… Дело было вечером, делать было нечего, решил я зайти в putty и помониторить свою VDS, и с ужасом наблюдал картину, где мне показывало что свободно всего 40Мб оперативной памяти из 512. Ведь на ней висел всего один проект, и нам нем посещалка почти нулевая. Решил я это дело как-то исправлять. Тогда у меня стоял такой набор софта: CentOS, apache, php, memcache, eaccelerator, mysql, sphinx и ISPManager. Это джентльменский набор + несколько пакетов для корректной работы LS. Я всегда знал, что апач кушает очень много памяти, и при неграмотном подходе работает очень медленно.

И вот, решил я избавиться от апача, пойти в сторону лучшей, и менее известной альтернативы — nginx + php-cgi. Об этом и пойдет речь этом топике.


У меня на сайте база данных из ~2000 блогов, что для LiveStreet «из коробки» очень и очень много. На самом деле, вся оптимизация пришлась на сам движок, но и VDS не оставалась в стороне. До моих манипуляций с ОСью, мой сайт загружался примерно за 2-3 секунды, после оптимизации время загрузки сократилось вдвое! Раньше, главная страница грузилась 1.231 секунды, сейчас она загружается за 0.465 секунды. По-моему, это очень и очень неплохой результат, особенно для подобного сайта и для такой слабой VDS. Ну да ладно, хватит уже скучного предисловия, перейдем к делу.

В данном гайде я опишу как нам установить на чистый Debian 5.0 «lenny» пакеты: nginx, php-cgi, eaccelerator, memcache, sphinx и mysql.

Я буду описывать установку на VDS с такими конфигами:
RAM: 512 Мб
CPU: 600 MHz (одно ядро)
При этом, после оптимизации VDS у меня было свободно порядка 250 мегабайт оперативной памяти, вместо жалких 40.

Для начала нам необходимо обновить список пакетов:
apt-get update

Далее нам надо поставить пакет, для ручной установки:
apt-get install build-essential

nginx [engine x]



Устанавливаем библиотеки для установки nginx нашей конфигурации (установка pcre обязательна, ssl — при необходимости):
apt-get install libpcre3-dev
apt-get install openssl
apt-get install libcurl4-openssl-dev


Т.к. в репозиториях Debian лежит старая версия nginx, мы будет устанавливать ее вручную, перейдем в каталог для временных файлов:
cd /tmp

Качаем последнюю версию nginx (если страшно устанавливать последнюю, можете установить последнюю стабильную версию, а забрать можете их тут), распаковываем и заходим в папку установки:
wget http://sysoev.ru/nginx/nginx-0.9.6.tar.gz
tar -zxvf nginx-0.9.6.tar.gz
cd nginx-0.9.6


Теперь конфигурируем и устанавливаем:
./configure \
--user=www-data \
--group=www-data \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gzip_static_module \
--with-mail \
--with-mail_ssl_module
make
make install


Запускаем установленный nginx:
/usr/local/nginx/sbin/nginx

В браузере набираем ip или домен VDS, и если мы видим:

Welcome to nginx!

Значит, всё хорошо. Теперь нам нужно добавить nginx в автозагрузку. Для этого создаем файл '/etc/init.d/nginx'

touch /etc/init.d/nginx

Следующего содержания:

#! /bin/sh

### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/nginx/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
. /etc/default/nginx
fi

set -e

case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
sleep 1
start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/nginx.pid --exec $DAEMON
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

exit 0


Делаем исполняемым и добавляем наш nginx в автозагрузку:
chmod 755 /etc/init.d/nginx
update-rc.d nginx defaults


Теперь мы можем управлять нашим http-сервером с помощью следующих команд:
/etc/init.d/nginx start
/etc/init.d/nginx restart
/etc/init.d/nginx stop


php-fastcgi



PHP лучше ставить из коллекции пакетов. Сейчас там лежит стабильная версия 5.2.6 — не последняя, зато стабильно работает. Устанавливаем PHP с необходимыми для нас расширениями:
apt-get install php5-cgi php5-mysql php5-curl php5-gd php5-json php5-mcrypt php5-memcache

Далее заходим в каталог '/etc/php5/cgi/php.ini', где добавляем строку в конец файла:
cgi.fix_pathinfo = 1

Добавим php в автозагрузку, для чего создаем скрипт '/etc/init.d/php-fastcgi'
touch /etc/init.d/php-fastcgi
Следующего содержания:
#! /bin/sh
### BEGIN INIT INFO
# Provides: php-fastcgi
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start and stop php-cgi in external FASTCGI mode
# Description: Start and stop php-cgi in external FASTCGI mode
### END INIT INFO

# Author: Kurt Zankl <kz@xon.uni.cc>

# Do NOT "set -e"

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="php-cgi in external FASTCGI mode"
NAME=php-fastcgi
DAEMON=/usr/bin/php-cgi
PIDFILE=/var/run/$NAME.pid
scriptNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# If the daemon is not enabled, give the user a warning and then exit,
# unless we are stopping the daemon
if [ "$START" != "yes" -a "$1" != "stop" ]; then
log_warning_msg "To enable $NAME, edit /etc/default/$NAME and set START=yes"
exit 0
fi

# Process configuration
export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS
DAEMON_ARGS="-q -b $FCGI_HOST:$FCGI_PORT"

do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --background --make-pidfile --chuid $EXEC_AS_USER --startas $DAEMON -- $DAEMON_ARGS || return 2
}

do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE > /dev/null # --name $DAEMON
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}

case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $scriptNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac


Делаем наш скрипт исполяемым:
chmod 755 /etc/init.d/php-fastcgi

Создаем другой файл '/etc/default/php-fastcgi'
touch /etc/default/php-fastcgi
С таким содержанием:
#
# Settings for php-cgi in external FASTCGI Mode
#

# Should php-fastcgi run automatically on startup? (default: no)
START=yes

# Which user runs PHP? (default: www-data)
EXEC_AS_USER=www-data

# Host and TCP port for FASTCGI-Listener (default: localhost:9000)
FCGI_HOST=localhost
FCGI_PORT=9000

# Environment variables, which are processed by PHP
PHP_FCGI_CHILDREN=5
PHP_FCGI_MAX_REQUESTS=1000


Запускаем php-fastcgi:
/etc/init.d/php-fastcgi start

Добавляем в автозагрузку:
update-rc.d php-fastcgi defaults

Теперь нам надо совместить NGINX и PHP



Создадим папку для сайтов, например, '/home/www', где будет лежать наш сайт на LiveStreet:

mkdir /home/www

Редактируем '/usr/local/nginx/conf/nginx.conf':
nano /usr/local/nginx/conf/nginx.conf
В этом конфиге необходимо указать под кем будем запускать nginx, первую строку заменяем на:

user www-data www-data;

В контейнере server {} добавим следующие строки:

location / {
root /home/www;
index index.php index.html index.htm;
}

location ~ \.php$ {
root /home/www;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param script_FILENAME /home/www$fastcgi_script_name;
include fastcgi_params;
}

location / {
root /home/www;
index index.php;
if (!-f $request_filename){
set $rule_0 1$rule_0;
}
if (!-d $request_filename){
set $rule_0 2$rule_0;
}
if ($rule_0 = "21") {
rewrite ^/(.*)$ /./index.php;
}
}


Для лучшей оптимизации nginx, я советую почитать блог.

Перезапускаем nginx:
/etc/init.d/nginx restart

Создаем файл для теста '/home/www/info.php':
touch /home/www/info.php
Следующего содержания:
<?php
phpinfo();
?>


Проверяем в браузере — httр://ваш-адрес/info.php

MYSQL



Устанавливаем:
apt-get install mysql-server mysql-client

EACCELERATOR



Т.к. пакет eAccelerator отсутствует в репозиториях Debian, мы будем ставить его вручную. Предварительно нам потребуется установить библиотеку php-developer:
apt-get install php5-dev

Теперь скачиваем и устанавливаем eAccelerator:
cd /tmp
wget httр://bart.eaccelerator.net/source/0.9.5.3/eaccelerator-0.9.5.3.tar.bz2
tar xvfj eaccelerator-0.9.5.3.tar.bz2
cd eaccelerator-0.9.5.3
phpize
./configure
make
make install


Создаем конфигурационный файл '/etc/php5/conf.d/eaccelerator.ini':
touch /etc/php5/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"


Создаем папку для хранения файлов кеша eAccelerator'а:
mkdir -p /var/cache/eaccelerator
chmod 0777 /var/cache/eaccelerator


Перезапускаем php:
/etc/init.d/php-fastcgi restart

memcache



Устанавливаем:
apt-get install memcached

Перезапускаем php ещё разок:
/etc/init.d/php-fastcgi restart

Sphinx search



Устанавливаем:

wget http://sphinxsearch.com/files/sphinx-0.9.9.tar.gz
tar –xzvf sphinx-0.9.9.tar.gz
cd sphinx-0.9.9
./configure
make
make install


Теперь для нормального функционирования sphinx'а на LiveStreet нам придется изменить его, для этого откроем файл конфигурации:

nano /usr/local/etc/sphinx.conf

Удалим там все, что есть, и добавим следующие строки:

#######################
#
# Описываем индексы
#
#######################

# Источник-родитель для всех остальных источников. Здесь указываются параметры доступа
# к базе данных сайта
source lsParentSource
{
type = mysql
sql_host = <your_database_host>
sql_user = <your_database_login>
sql_pass = <your_database_password>
sql_db = <your_database_name>
sql_port = 3306
# Для ускорения работы прописываем путь до MySQL-го UNIX-сокета (чтобы
# операции с БД происходили не через TCP/IP стек сервера)
sql_sock = /var/run/mysqld/mysqld.sock


mysql_connect_flags = 32

# Включам нужную кодировку соединения и выключаем кеш запросов
sql_query_pre = SET NAMES utf8
sql_query_pre = SET SESSION query_cache_type=OFF
}

# Источник топиков
source topicsSource : lsParentSource
{
# запрос на получения данных топиков
sql_query = \
SELECT t_fast.topic_id, t_fast.topic_title, UNIX_TIMESTAMP(t_fast.topic_date_add) as topic_date_add, \
tc.topic_text, t_fast.topic_publish \
FROM prefix_topic as t_fast, prefix_topic_content AS tc \
WHERE t_fast.topic_id=tc.topic_id AND t_fast.topic_id>=$start AND t_fast.topic_id<=$end

# запрос для дробления получения топиков на неколько итераций
sql_query_range = SELECT MIN(topic_id),MAX(topic_id) FROM prefix_topic

# сколько получать объектов за итерацию
sql_range_step = 1000

# Указываем булевый атрибут критерия "топик опубликован". Для возможности указания этого критерия при поиске
sql_attr_bool = topic_publish

# Атрибут даты добавления, типа "время"
sql_attr_timestamp = topic_date_add

# мульти-аттрибут "теги топика"
sql_attr_multi = uint tag from query; SELECT topic_id, topic_tag_id FROM prefix_topic_tag

sql_ranged_throttle = 0
}

# Источник комментариев
source commentsSource : lsParentSource
{
sql_query = \
SELECT comment_id, comment_text, UNIX_TIMESTAMP(comment_date) as comment_date, comment_delete \
FROM prefix_comment \
WHERE target_type='topic' AND comment_id>=$start AND comment_id<=$end

sql_query_range = SELECT MIN(comment_id),MAX(comment_id) FROM prefix_topic_comment
sql_range_step = 5000

sql_attr_bool = comment_delete
sql_attr_timestamp = comment_date
}

#######################
#
# Описываем индексы
#
#######################

index topicsIndex
{
# Источник, который будет хранить данный индекса
source = topicsSource
path = /usr/local/SphinxIndex/topicsSource

# Тип хранения аттрибутов
docinfo = extern

mlock = 0

# Используемые морфологические движки
morphology = stem_enru, soundex, metaphone

# Кодировака данных из источника
charset_type = utf-8

# Из данных источника HTML-код нужно вырезать
html_strip = 1
}

# Индекс комментариев
index commentsIndex
{
source = commentsSource
path = /usr/local/SphinxIndex/commentsSource

docinfo = extern

mlock = 0

morphology = stem_enru, soundex, metaphone

charset_type = utf-8
}

#######################
#
# Настройки индексатора
#
#######################

indexer
{
# Лимит памяти, который может использавать демон-индексатор
mem_limit = 32M
}

#######################
#
# Настройка демона-поисковика
#
#######################

searchd
{
# Адрес, на котором будет прослушиваться порт
address = 127.0.0.1

# Ну и собственно номер порта демона searchd
port = 3312

# Лог-файл демона
log = /var/log/sphinx/searchd.log

# Лог поисковых запросов. Если закомментировать,то логировать поисковые строки не будет
query_log = /var/log/sphinx/query.log

# Время в секундах, которое ждет демон при обмене данными с клиентом. По исчерпании происходит разрыв коннекта
read_timeout = 5

# Максимальное количество одновременно-обрабатываемых запросов. 0 означает дофига, а точнее без ограничения
max_children = 30

# Файл, в который сохраняется PID-процесса при запуске
pid_file = /var/log/sphinx/searchd.pid
}


Теперь нам надо создать каталоги для кеша поиска:

mkdir -p /usr/local/SphinxIndex
mkdir -p /usr/local/SphinxIndex/commentsSource
mkdir -p /usr/local/SphinxIndex/topicsSource
chmod -R 777 /usr/local/SphinxIndex/
chmod -R 777 /usr/local/commentsSource/
chmod -R 777 /usr/local/topicsSource/


Запускаем индексацию:

/usr/local/bin/indexer --all

Запускаем демона поиска:

/usr/local/bin/searchd

Далее останется лишь прописать сфинкс в крон:

nano /etc/crontab

Добавляем:

0 */3 * * * /usr/local/bin/indexer --all --rotate

Это значит, что крон будет запускать индексацию каждые 3 часа.

P.S: Если найдете грамматические или синтаксические ошибки, сильно не пинайте.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.