Оптимизация VPS сервера

25 August 2010 #vps#nginx

После покупки VPS сервера возникает масса проблем. Нужно выбрать веб-сервер, фтп-сервер, почтовый сервер. Нужно продумать принципы организации работы веб-сервера с отдельными модулями.

Проблемы начинают проявлять себя непосредственно в работе. То памяти чересчур много расходуется, то процессор работает постоянно на максимуме, то начинает сказываться низкая скорость работы жесткого диска, то еще что-нибудь.

Вот тут и наступает момент необходимости оптимизации. Когда установленные программы начинают настраивать, тестировать, опять настраивать.

Вводная

Напомню лишь, что я использую VPS от linode.com, минимальный тариф с 512 мегабайтами оперативной памяти и 4-х ядерных процессором. Установленная операционная система Ubuntu 10.04. В качестве веб-сервера используется Nginx + php5-fpm + XCache.

Я проводил уже стресс-тест производительности, результаты описывал в статье Тест производительности VPS сервера. И на тот момент, сервер показал результат в 14.15 запроса/сек. Для того, чтобы выдержать посещаемость моего сайта этого результата вполне достаточно, но стала ощущаться другая проблема. В нагрузке чрезмерно расходовалась оперативная память.

500 запросов вполне хватало для того, чтобы процессы php заполняли всю оперативную память, вытесняя попутно все буферы и кеши, а затем и весь своп. Продолжение подобной стрессовой нагрузки могли просто уронить сервер. И это меня очень сильно стало беспокоить.

Я просто не понимал, почему php5-fpm начинает так сильно расходовать оперативную память. Как вообще в подобных условиях живут другие проекты?

Пытался изменять число процессов и nginx и php5-fpm, уменьшая до минимума, однако это давало только лишние минуты работы, но не избавляло от самой проблемы. Два процесса php5-fpm точно так же заполняли все пространство выделенной памяти, как и все восемь. Пришлось на время оставить минимальное число процессов, для того, чтобы дольше выдерживать нагрузку и искать решение.

Еще немного спасло положение изменение настроек php5-fpm. В файле /etc/php5/fpm/php5-fpm.conf изменил следующие значения:

emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 5s
pm.max_requests = 500

Стало чуть легче. Теперь спустя определенное время процессы php5-fpm стали перезапускаться, высвобождая занятую память. Но утечки продолжались.

Memcached

Сегодня решил попробовать в работе модуль memcached. Перед этим пришлось думать и решать, стоит ли это делать, так как на дополнительный модуль потребуется выделить определенное количество оперативной памяти, а ее и так катастрофически не хватало. Решил все таки рискнуть и посмотреть, что выйдет. Все равно на сайте нагрузка не большая. Устанавливаем и запускаем:

# apt-get install memcached php5-memcache
# /etc/init.d/memcached start

Теперь необходимо прописать использование memcached в php5-fpm, для этого изменяем файл /etc/php5/fpm/php.ini и в самое начало, после директивы [PHP] прописываем:

extension=memcache.so

Теперь перезапускаем php:

# /etc/init.d/php5-fpm restart

И смотрим, появился ли блок memcache в выводе функции phpinfo(), если появилось, значит все нормально. Единственно, перед самим запуском memcached я еще изменил его настройки, увеличив используемую память с 16 мегабайт до 64.

Последующий стресс-тест поверг меня в недоумение! Производительность не изменилась, но утечки памяти просто исчезли. Прекратился этот дикий расход оперативной памяти.

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

ps -e | grep 'memcached'  | awk '{print $0}{sum+=$1} END {print "\nMemory usage for memcached:", sum/1024, "MB\n"}'

Результат – чуть больше 6 мегабайтов оперативной памяти. То есть 64 мегабайта, что я выделил, с лихвой хватает на все.

Тесты

Провел ряд тестов, для того, чтобы отследить, какое число процессов nginx и php5-fpm является оптимальным для использования на VPS от Linode на минимальном тарифе. Для этого, как и в прошлый раз, использовал утилиту ab из поставки веб-сервера apache. Запускал следующим образом:

ab -n 1000 -n 50 http://domain.ru/index.php

Увеличил число запросов до 1000 и увеличил число одновременных запросов к серверу до 50. Меня интересовал расход оперативной памяти и естественно, производительность веб-сервера, то есть сколько запросов он сможет обрабатывать в секунду.

Для этого я изменял число процессов nginx, затем число процессов php5-fpm и наблюдал за показаниями утилиты htop.

Первый тест проводил с тем же числом процессов, что использовал до установки memcached.

2 nginx и 2 php5-fpm:

Concurrency Level:      50
Time taken for tests:   89.755 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      283000 bytes
HTML transferred:       0 bytes
Requests per second:    11.14 [#/sec] (mean)
Time per request:       4487.736 [ms] (mean)
Time per request:       89.755 [ms] (mean, across all concurrent requests)
Transfer rate:          3.08 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       4
Processing:  1656 4379 320.6   4390    6135
Waiting:     1656 4379 320.6   4390    6135
Total:       1661 4379 320.3   4390    6137

Максимальный расход памяти при этом 123Mb. Свободной памяти еще много, а вот производительность невысока, заметно, что в работе участвуют только два из четырех выделенных ядер. Увеличиваем число php процессов до 4.

2 nginx и 4 php5-fpm:

Concurrency Level:      50
Time taken for tests:   46.838 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      283000 bytes
HTML transferred:       0 bytes
Requests per second:    21.35 [#/sec] (mean)
Time per request:       2341.875 [ms] (mean)
Time per request:       46.838 [ms] (mean, across all concurrent requests)
Transfer rate:          5.90 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       5
Processing:   401 2287 225.4   2286    3039
Waiting:      401 2286 225.4   2286    3039
Total:        406 2287 225.0   2286    3041

Максимальный расход памяти в данном случае 157Mb. Количество обрабатываемых запросов выросло почти в два раза. Не плохо. Пробуем увеличить число процессов nginx, по сути должно вырасти значение максимального количества одновременных соединений.

4 nginx и 4 php5-fpm:

Concurrency Level:      50
Time taken for tests:   45.951 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      283000 bytes
HTML transferred:       0 bytes
Requests per second:    21.76 [#/sec] (mean)
Time per request:       2297.534 [ms] (mean)
Time per request:       45.951 [ms] (mean, across all concurrent requests)
Transfer rate:          6.01 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       4
Processing:   494 2239 214.0   2245    2988
Waiting:      494 2239 214.0   2245    2988
Total:        498 2240 213.6   2245    2990

Максимальный расход памяти в этом случае 154Mb. Что даже чуть меньше чем в предыдущем случае, что немного странно. Однако число запросов, которое обрабатывает сервер каждую секунду, осталось неизменным. Имеет ли тогда смысл держать запущенными несколько nginx??

1 nginx и 4 php5-fpm:

Concurrency Level:      50
Time taken for tests:   46.050 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      283000 bytes
HTML transferred:       0 bytes
Requests per second:    21.72 [#/sec] (mean)
Time per request:       2302.504 [ms] (mean)
Time per request:       46.050 [ms] (mean, across all concurrent requests)
Transfer rate:          6.00 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       4
Processing:   527 2246 201.0   2260    2968
Waiting:      526 2246 201.0   2260    2968
Total:        531 2246 200.6   2260    2969

Максимальный расход памяти 151Mb. Как видим, на расход памяти это влияет мало, и на число обрабатываемых запросов тоже. Пока не вижу смысла запускать дополнительные процессы nginx.

Стало интересно, а что будет, если поставить число запущенных php-процессов больше, чем число ядер??

1 nginx и 8 php5-fpm:

220 Mb max
Concurrency Level:      50
Time taken for tests:   47.617 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Non-2xx responses:      1000
Total transferred:      283000 bytes
HTML transferred:       0 bytes
Requests per second:    21.00 [#/sec] (mean)
Time per request:       2380.835 [ms] (mean)
Time per request:       47.617 [ms] (mean, across all concurrent requests)
Transfer rate:          5.80 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.2      0       7
Processing:   544 2331 202.2   2336    3307
Waiting:      544 2331 202.2   2336    3307
Total:        549 2331 201.9   2336    3312

Максимальный расход памяти составил 220Mb. Число запросов даже несколько упало, изменения нет. То есть фактически увеличивать число процессов php выше 4 для моего сервера вряд ли стоит.

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

Во всех тестах использовалось расширение WP Super Cache. При тесте, естественно были задействованы кешированные страницы, что довольно неплохо поднимало скорость отдачи странички и уменьшало время ее генерации. Администратор по умолчанию работает с некешированными страницами и на скорость влияет только производительность PHP-интерпретатора. Хотя и был установлен модуль php5-xcache, в админке былы заметны некие тормоза.

До этого момента использовал настройки XCache по умолчанию. решил немного повозиться и поискать варианты конфигураций в сети интернет. Изменил лишь несколько настроек в файле /etc/php5/conf.d/xcache.ini:

xcache.size  =               64M
xcache.count =                 4
xcache.var_size  =           64M

Значение xcache.size увеличил с 16 до 64 мегабайт. Параметр xcache.count указывает на количество используемых на машине ядер, установил в 4. И xcache.var_size изменил с 0 на 64 мегабайта.

После перезапуска php5-fpm, и админка стала более отзывчивой!

Выводы

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

С помощью тестов мне удалось значительно снизить потребление оперативной памяти. И при этом достичь показателей обрабатываемых запросов к серверу до 21.72. Что выше, чем даже у настроенного шаред-хостинга, что я использовал раньше.

Совершенно не ожидал, что установка memcached позволит мне решить проблему с утечками памяти. Теперь же настоятельно рекомендую использовать этот модуль PHP на серверах, размещающих в себе WordPress.

После проведенных тестов загорелся довести обрабатываемое число запросов до 100 в секунду. Правда понимаю, что именно сейчас это вряд ли возможно, так как во время тестов все упиралось в производительность процессора. Буду искать варианты оптимизации PHP-приложения.

Ждите продолжения!