Тестирование apache MPM с помощью yandex-tank

 Posted on July 2, 2017 at 10 p.m.

Статья про тестирование 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>

Запускаем тест и получаем такую картину:
Prefork code mod_php
Держим 7-8 rps, а дальше упираемся в потолок cpu, но несмотря на то, что нагрузку не выдерживаем, сервисы не падают и продолжают нормально работать после завершения теста.
Prefork cpu mod_php

prefork+php-fpm

Теперь заменяем mod_php на php-fpm. В такой конфигурации один процесс apache у меня занимал 1.8Mb RAM, php-fpm - 30Mb.
Запускаем тест с той же конфигурацией:
Prefork php-fpm 1
Тут мы уже держим 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 - чуда не произошло.
Worker php-fpm

event+php-fpm

Конфигурацию оставляем прежней:

<IfModule event.c>
StartServers         4
MaxRequestWorkers   20
MinSpareThreads      5
MaxSpareThreads     20
ThreadsPerChild      5
MaxRequestsPerChild  0
</IfModule>

Event php-fpm
В этом случае уже уверенно держим 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.