Тестирование apache MPM с помощью yandex-tank
Тестирование - один из важнейших этапов жизненного цикла системы, оно помогает нам понять насколько хорошо она работает, где у нее слабые места и что в ней можно улучшить. Давно уже хотел опробовать yandex-tank, и вот этот момент настал. Сегодня я поделюсь своим опытом работы с этим инструментом.
Содержание:
Подготовка
Для тестов я взял виртуальный сервер у servers.ru SSD30 (1 vCPU 1024 MB RAM 30 GB SSD) Centos 7. Регистрируемся в overload.yandex.net и получаем api key (они зачем-то запрятали токен, для того чтобы его получить нужно нажать на свою аватарку в правом верхнем углу и там будет "My api token"). Устанавливаем у себя yandex-tank. Так как для компонента Phantom требовался gcc < 4.9, то я решил использовать Docker-образ. Вообще, последнее время мне все больше и больше нравится Docker, с помощью него можно быстро протестировать какую-нибудь программу или конфигурацию, не засоряя себе систему, так что если вы еще не пробовали - советую. Тестировать будем свежую установку WordPress запрашивая главную страницу.
Подготавливаем файлы для запуска тестов:
tank
|- ssh
| |- id_rsa <- cloud private key
|- load.ini
|- monitoring.cfg
|- token.txt <- yandex-overload api key
load.ini:
[tank]
plugin_uploader=yandextank.plugins.DataUploader overload
[telegraf]
config=monitoring.cfg
[overload]
token_file=token.txt
[phantom]
address= xxx.xxx.xxx.xxx ;Target's address
port=80
rps_schedule= step(3, 15, 1, 10)
header_http = 1.1
headers = [Host: www.test.com]
[Connection: close]
uris = /
[autostop]
autostop=http(5xx,100%,5s)
net(110,1,30)
monitoring.cfg:
<Monitoring>
<Host address="xxx.xxx.xxx.xxx" username="PUT_HERE_USERNAME">
<CPU measure="user,system,iowait"/>
<System measure="csw,int"/>
<Memory measure="free,used"/>
<Disk measure="read,write"/>
<Net measure="recv,send"/>
</Host>
</Monitoring>
Запускаются тесты командой:
docker run -v $(pwd):/var/loadtest -v $(pwd)/ssh:/root/.ssh --net host -it direvius/yandex-tank
В тестовой среде развернуто:
- Apache 2.4.6 (prefork)
- MariaDB 5.5.52
- php 5.4.16 (подключен как модуль)
- WordPress 4.8 (плагины и темы по умолчанию)
Тест с базовыми настройками выглядит очень печально. Все ложится на 6 rps (Requests per second), чего и следовало ожидать.
# dmesg | grep "Out of memory:"
[ 4702.295815] Out of memory: Kill process 24217 (mysqld) score 88 or sacrifice child
[ 4705.164862] Out of memory: Kill process 23805 (httpd) score 30 or sacrifice child
[ 4706.544895] Out of memory: Kill process 23861 (httpd) score 29 or sacrifice child
[ 4707.523879] Out of memory: Kill process 23875 (httpd) score 29 or sacrifice child
[ 4708.574006] Out of memory: Kill process 23858 (httpd) score 29 or sacrifice child
Теперь займемся расчетами (в этот раз мы не ставим перед собой цель все оптимизировать, просто анализируем сколько сможем вытянуть rps из различных MPM, выжимать максимум из сервера будем в другой статье):
- отдадим системе 300Mb
- выделим MariaDB 300Mb
- Apache+PHP 400Mb
Подправим конфигурационный файл MariaDB (ни в коем случае не копируйте эти настройки, они просто ограничивают потребление памяти сервером и являются далеко не самыми оптимальными. Про настройку и оптимизацию БД читайте в следующих статьях):
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
key_buffer_size=2M
max_connections=40
innodb_buffer_pool_size=8M
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
!includedir /etc/my.cnf.d
prefork+mod_php
Первым делом рассчитываем сколько памяти потребляет один процесс apache (метод описан в предыдущей статье). У меня получилось с подключенным модулем php, без нагрузки - 18Mb, после запуска теста - 32Mb. Итого мы можем себе позволить 400/32=12 процессов apache.
<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 12
ServerLimit 12
MaxRequestWorkers 12
MaxRequestsPerChild 4000
</IfModule>
Запускаем тест и получаем такую картину:
Держим 7-8 rps, а дальше упираемся в потолок cpu, но несмотря на то, что нагрузку не выдерживаем, сервисы не падают и продолжают нормально работать после завершения теста.
prefork+php-fpm
Теперь заменяем mod_php на php-fpm. В такой конфигурации один процесс apache у меня занимал 1.8Mb RAM, php-fpm - 30Mb.
Запускаем тест с той же конфигурацией:
Тут мы уже держим 8-9 rps и опять упираемся в cpu. Ради эксперимента приведем конфигурацию apache к:
<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 16
ServerLimit 16
MaxRequestWorkers 16
MaxRequestsPerChild 4000
</IfModule>
Результат остается прежним 8-9 prs.
worker+php-fpm
Конфигурация для worker:
<IfModule worker.c>
StartServers 4
MaxRequestWorkers 20
MinSpareThreads 5
MaxSpareThreads 20
ThreadsPerChild 5
MaxRequestsPerChild 0
</IfModule>
Запускаем тест и наблюдаем все те же 8-9 rps - чуда не произошло.
event+php-fpm
Конфигурацию оставляем прежней:
<IfModule event.c>
StartServers 4
MaxRequestWorkers 20
MinSpareThreads 5
MaxSpareThreads 20
ThreadsPerChild 5
MaxRequestsPerChild 0
</IfModule>
В этом случае уже уверенно держим 9 rps.
Выводы
- На стартовом тарифе мы во всех случаях уперлись в производительность cpu. Такой результат - тоже результат. Большую нагрузку создает выполнение php-скриптов, вероятно тест на статических файлах смог бы лучше раскрыть преимущества worker и event.
- В нашем случае стоит проводить оптимизацию разгружая cpu (включить кэширование, провести тест с отключенным SELinux, оптимизировать систему).
- Event + php-fpm показал наилучший результат.
- Php-fpm работает лучше mod_php (в конфигурациях по умолчанию).
- Рассчитав параметры работы сервера БД и apache мы добились стабильной работы сервисов (под нагрузкой они не падали и продолжали нормально работать после окончания теста).
P.S. Планирую подготовить серию статей по оптимизации, после чего постараюсь выжать максимум из этой конфигурации сервера и сравню результаты с текущими. Теперь, когда у меня есть цифры от которых можно отталкиваться, я смогу проводить тесты с различными конфигурациями на различном оборудовании и анализировать результаты.
UPD: Подвернулся для тестирования сервер DELL 1950 / Dual Xeon 5110 (1.6GHz) / 4GB RAM, Centos 6.9, Apache 2.2.29 (prefork). При рассчитанных параметрах на тесте со стандартной темой WordPress получилось 22 rps, но вот что интересно, если завысить MaxClients (MaxRequestWorkers) сервер начинает активно использовать swap и в итоге получаем 13 rps. Отсюда вывод: не следует решать проблему нехватки памяти за счет использования swap.