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

30 марта 2011 г.

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

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

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

У меня на сайте база данных из ~2000 блогов, что для LiveStreet «из коробки» очень и очень много. На самом деле, вся оптимизация пришлась на сам движок, но и VDS не оставалась в стороне. До моих манипуляций с ОСью, мои сайты на LiveStreet загружались примерно за 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.

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

1
apt-get update

Далее нам надо поставить пакет, для ручной установки:

1
apt-get install build-essential

nginx [engine x]

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

1
2
3
apt-get install libpcre3-dev
apt-get install openssl
apt-get install libcurl4-openssl-dev


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

1
cd /tmp

Качаем последнюю версию nginx (если страшно устанавливать последнюю, можете установить последнюю стабильную версию, а забрать можете их тут), распаковываем и заходим в папку установки:

1
2
3
wget <a class="external" title="Откроется в новом окне - sysoev.ru" target="_blank" href="http://sysoev.ru/nginx/nginx-0.9.6.tar.gz">sysoev.ru/nginx/nginx-0.9.6.tar.gz</a>
tar -zxvf nginx-0.9.6.tar.gz
cd nginx-0.9.6

Теперь конфигурируем и устанавливаем:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
./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:

1
/usr/local/nginx/sbin/nginx

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

Welcome to nginx!

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

1
touch /etc/init.d/nginx

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#! /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 в автозагрузку:

1
2
chmod 755 /etc/init.d/nginx
update-rc.d nginx defaults

Теперь мы можем управлять нашим http-сервером с помощью следующих команд:

1
2
3
/etc/init.d/nginx start
/etc/init.d/nginx restart
/etc/init.d/nginx stop

php-fastcgi

PHP лучше ставить из коллекции пакетов. Сейчас там лежит стабильная версия 5.2.6 — не последняя, зато стабильно работает. Устанавливаем PHP с необходимыми для нас расширениями:

1
apt-get install php5-cgi php5-mysql php5-curl php5-gd php5-json php5-mcrypt php5-memcache

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

1
cgi.fix_pathinfo = 1

Добавим php в автозагрузку, для чего создаем скрипт ‘/etc/init.d/php-fastcgi’

1
touch /etc/init.d/php-fastcgi

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

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#! /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

Делаем наш скрипт исполяемым:

1
2
3
4
chmod 755 /etc/init.d/php-fastcgi[/code
 
Создаем другой файл '/etc/default/php-fastcgi'
touch /etc/default/php-fastcgi

С таким содержанием:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
#
# 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:

1
/etc/init.d/php-fastcgi start

Добавляем в автозагрузку:

1
update-rc.d php-fastcgi defaults

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

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

1
mkdir /home/www

Редактируем '/usr/local/nginx/conf/nginx.conf':

1
nano /usr/local/nginx/conf/nginx.conf

В этом конфиге необходимо указать под кем будем запускать nginx, первую строку заменяем на:

1
user www-data www-data;

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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:

1
/etc/init.d/nginx restart

Создаем файл для теста '/home/www/info.php':

1
touch /home/www/info.php

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

1
2
3
<?php
phpinfo();
?>

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

MYSQL

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

1
apt-get install mysql-server mysql-client

EACCELERATOR

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

1
apt-get install php5-dev

Теперь скачиваем и устанавливаем eAccelerator:

1
2
3
4
5
6
7
8
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':

1
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'а:

1
2
mkdir -p /var/cache/eaccelerator
chmod 0777 /var/cache/eaccelerator

Перезапускаем php:

1
/etc/init.d/php-fastcgi restart

memcache

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

1
apt-get install memcached

Перезапускаем php ещё разок:

1
/etc/init.d/php-fastcgi restart

Sphinx search

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

1
2
3
4
5
6
wget <a class="external" title="Откроется в новом окне - sphinxsearch.com" target="_blank" href="http://sphinxsearch.com/files/sphinx-0.9.9.tar.gz">sphinxsearch.com/files/sphinx-0.9.9.tar.gz</a>
tar –xzvf sphinx-0.9.9.tar.gz
cd sphinx-0.9.9
./configure
make
make install

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

1
nano /usr/local/etc/sphinx.conf

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

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

# Источник-родитель для всех остальных источников. Здесь указываются параметры доступа
# к базе данных сайта
source lsParentSource
{
type = mysql
sql_host =
sql_user =
sql_pass =
sql_db =
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 }

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

1
2
3
4
5
6
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/

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

1
/usr/local/bin/indexer --all

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

1
/usr/local/bin/searchd

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

1
nano /etc/crontab

Добавляем:

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

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

Теги: рубрика Linux, Сайтостроение
  • Похожие статьи
  • Предыдущие из рубрики