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

Общие принципы
Компоненты OTRS, рассматриваемые в процессе оптимизации производительности:
- Apache Web Server (mod_perl) - сервер приложений
- OTRS Framework (непосредственно сам OTRS) - приложение, исполняемое под Apache
- База данных (в нашем примере - PostgreSQL)
- Кэш бэкенда

Ключевые принципы, на которые стоит обращать внимание при построении высоконагруженной конфигурации OTRS:
- Размещение веб-сервера Apache и базы данных на разных серверах
- При нагрузке > 100 одновременно работающих пользователей рекомендуется использовать несколько серверов приложений, с балансировкой нагрузки при помощи nginx или DNS Round Robin.
- Кэш OTRS (/opt/otrs/var/tmp) должен размещаться на высокопроизводительном дисковом разделе (предпочтительно SSD или ramdisk). Альтернативы - in-memory базы кэша (Redis или memcached).
- Выбор Kernel::System::Ticket::IndexAccelerator::StaticDB в качестве TicketIndexModule
- Тюнинг поискового индекса (Ticket Search Index)
- В качестве хранилища вложений использовать файловую систему вместо базы (Kernel::System::Ticket::Article::Backend::MIMEBase::ArticleStorageFS). Если используется несколько серверов приложений, необходимо обеспечить общий доступ к файловому хранилищу (NFS / iSCSI).
Оптимальные настройки Apache Web Server
Обязательно использование модуля многопроцессовой обработки mpm_prefork. В Debian 9 веб-сервер Apache поставляется с включенным по-умолчанию mpm_event.
Проверить, какой модуль многопроцессности включен:
apachectl -t -D DUMP_MODULES | grep mpm

Отключить текущий модуль (на примере mpm_event, также может быть подключен mpm_worker) и включить mpm_prefork:
a2dismod mpm_event a2enmod mpm_prefork systemctl restart apache2
Проверить значения директив Apache (httpd.conf):
- HostnameLookups Off - отключить запросы Apache к DNS
- KeepAlive On - устанавливать постоянные соединения между сервером и клиентом. Экономия на повторной установке соединений.
- KeepAliveTimeout 30
- AllowOverride None - отключить использование .htaccess (рекомендуется прописывать настройки на уровне конфигураций виртуальных хостов)
- MaxRequestsPerChild - сколько запросов может обработать дочерний поток (mpm_event, mpm_worker) или процесс (mpm_prefork) перед тем, как его нужно будет перезапустить. Помогает предотвратить утечки памяти. В конфигурационном файле OTRS уже прописано оптимальное значение - 4000, однако не лишним будет перепроверить.
# Эти директивы позволяют заранее иметь в памяти созданные процессы, # чтобы не приходилось этого делать во время получения запроса # При запуска Apache создавать 3 процесса StartServers 3 # Apache не будет убивать свободные процессы, если их остается менее трех MinSpareServers 3 # Максимум 5 свободных процессов, остальные будут уничтожаться MaxSpareServers 5О директиве MaxClients поговорим отдельно. Она устанавливает максимальное число параллельно обрабатываемых сервером запросов.
Рассчитать ее для OTRS можно следующим образом:
- При пиковой нагрузке (или нагрузочном тестировании) выполнить команду:
ps -ylC /usr/sbin/apache2 | awk '{x += $8;y += 1} END {print "Average Proccess Size (MB): "x/((y-1)*1024)}'
Где /usr/sbin/apache2 - имя процесса Apache в вашей системе (например apache2 или httpd). - Команда отобразит средний объем процесса в мегабайтах (пример для OTRS Service Desk 6.0.5):
Average Proccess Size (MB): 74.7298
- Значение MaxCliens не должно превышать значения по формуле:
((Общие объем оперативной памяти)(MB) - Прочие процессы (MB) / Средний объем процесса (MB)
- Таким образом, для сервера с общим объемом памяти в 15 ГБайт (за вычетом памяти прочих процессов) и средним объемом процесса в 75 Мбайт, MaxClients должен быть примерно 200. Если указать заниженное значение MaxClients, избыточные соединения будут ожидать в очереди. Если завысить - есть риск, что сервер начнет использовать своп, что приведет к существенному падению производительности.
Проверить, включено ли сжатие gzip (mod_deflate):
apachectl -t -D DUMP_MODULES | grep deflate
Тюнинг СУБД
PostgreSQL (в отличие от MySQL) поставляется с оптимальными настройками производительности.
Несмотря на это, для ряда специфических задач должен производиться избирательный тюнинг (в ряде случаев вместе с доработкой API OTRS).
Инструменты в помощь разработчику: perl Dprof, EXPLAIN и профилирование "тяжелых" запросов к базе.
Подробнее с тюнингом PostgreSQL можно ознакомиться тут.
Нагрузочное тестирование
Нам понадобится отдельный хост-клиент, который мы будем использовать для тестирования и утилита siege (последняя версия на момент написания заметки - 4.0.4). Тестирование необходимо проводить либо на наработанной базе OTRS (>1000 тикетов, в этом случае шаг 1 можно пропустить), либо наполнить базу командой ниже:
- На сервере приложений OTRS генерируем заявки с использованием OTRS Console:
sudo -u otrs ./bin/otrs.Console.pl Dev::Tools::Database::RandomDataInsert \ --generate-tickets 1000 \ --articles-per-ticket 5
- В качестве нашего примера используется созданный в ходе написания предыдущей статьи экземпляр OTRS в Google Compute Engine
- На клиенте - с помощью curl -i или siege -g получить значение cookie (OTRSAgentInterface) для авторизации:
curl -i "http://192.168.75.72/otrs/index.pl?Action=Login&RequestedURL=Action%3DAgentDashboard%3B&Lang=ru&TimeOffset=-240&User=test&Password=test"
- На клиенте - подготовить файл urls.txt с перечнем ссылок для тестирования, пример:
http://192.168.75.72/otrs/index.pl?Action=AgentDashboard http://192.168.75.72/otrs/index.pl?Action=AgentDashboard http://192.168.75.72/otrs/index.pl?Action=AgentTicketQueue;QueueID=2;View= http://192.168.75.72/otrs/index.pl?Action=AgentTicketQueue;Filter=Unlocked;View=Small;QueueID=1; http://192.168.75.72/otrs/index.pl?Action=AgentTicketQueue;Filter=Unlocked;View=Medium;QueueID=3; http://192.168.75.72/otrs/index.pl?Action=AgentTicketStatusView http://192.168.75.72/otrs/index.pl?Action=AgentTicketStatusView;SortBy=Age;OrderBy=Down;View=;Filter=Closed http://192.168.75.72/otrs/index.pl?Action=AgentTicketEscalationView http://192.168.75.72/otrs/index.pl?Action=AgentTicketPhone http://192.168.75.72/otrs/index.pl?Action=AgentTicketEmail http://192.168.75.72/otrs/index.pl?Action=AgentStats;Subaction=Overview http://192.168.75.72/otrs/index.pl?Action=AgentStats;Subaction=EditSpecification;StatID=new http://192.168.75.72/otrs/index.pl?Action=AgentTicketSearch;Subaction=Search;TakeLastSearch=1;SaveProfile=1;Profile=good http://192.168.75.72/otrs/index.pl?Action=AgentTicketSearch;Subaction=Search;TakeLastSearch=1;SaveProfile=1;Profile=raw http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=596 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=59 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=51 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=70 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=94 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=95 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=96 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=121 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=202 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=256 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=265 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=266 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=267 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=290 http://192.168.75.72/otrs/index.pl?Action=AgentTicketZoom;TicketID=341 http://192.168.75.72/otrs/index.pl?Action=AgentTicketOwner;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketMerge;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPriority;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketHistory;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPending;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPhoneInbound;TicketID=600 http://192.168.75.72/otrs/index.pl?Action=AgentTicketOwner;TicketID=548 http://192.168.75.72/otrs/index.pl?Action=AgentTicketMerge;TicketID=219 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPriority;TicketID=592 http://192.168.75.72/otrs/index.pl?Action=AgentTicketHistory;TicketID=582 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPending;TicketID=254 http://192.168.75.72/otrs/index.pl?Action=AgentTicketPhoneInbound;TicketID=412
- По желанию, профили тестирования можно сегментировать в разрезе задач, например, выделив полнотекстовый поиск:
http://192.168.75.72/otrs/index.pl?Action=AgentTicketSearch&Subaction=Search&Fulltext=test&ResultForm=Normal&ShowAttributes=LabelFulltext&EmptySearch=1&ChallengeTocken=bQadwCSQgEP51LaK6wCkjPbrcN8Ba1HX
или отбор конфигурационных единиц CMDB:http://192.168.75.72/otrs/index.pl?Action=AgentITSMConfigItem;SortBy=Number;OrderBy=Down;View=;Filter=141
- Запуск тестирования (указать предварительно полученный cookie):
sudo siege -t5M -H "Cookie: OTRSAgentInterface=P6Etsr84UqvXramvD3JXDWIWLam1llOx" -i -c 100 -f
В приведенном выше примере 100 конкурентных пользователей будут нагружать приложение запросами в течение 5 минут, последовательно (в режиме регрессионного тестирования) перебирая список URL. Для случайной выборки - запустить siege с ключом -i.
Результат будет выведен следующим образом:Transactions: 68284 hits Availability: 100.00 % Elapsed time: 299.70 secs Data transferred: 3039.35 MB Response time: 0.41 secs Transaction rate: 227.84 trans/sec Throughput: 10.14 MB/sec Concurrency: 93.39 Successful transactions: 68284 Failed transactions: 0 Longest transaction: 6.72 Shortest transaction: 0.18
- Как альтернативу siege можно использовать стандартную утилиту ab (Apache Benchmark), к сожалению, неспособную работать со списком URL. Впрочем, в интернете попадаются и доработанные версии.
Интерпретация результатов
Transactions - число запросов к серверу за время тестированияAvailability - доступность сервера (% успешных соединений)
Elapsed time - продолжительность тестирования
Data transferred - объем данных, переданных сервером в ходе тестирования
Response time - среднее время отклика сервера
Transaction rate - производительность, среднее число запросов в секунду
Throughput - среднее количество данных, передаваемых в секунду
Concurrency - среднее число одновременных соединений
Successful transactions - число успешных соединений (код возврата HTTP < 400)
Failed transactions - число неуспешных соединений (код возврата HTTP 400 + socket timeout)
Longest transaction - продолжительность самой длинной транзакции
Shortest transaction - продолжительность самой короткой транзакции
Сравнение производительности mpm_prefork и mpm_event
Конфигурация тестового стенда- GCP Compute Engine n1-standard-4 (4 виртуальных ЦП, 15 ГБ памяти)
- Debian 9.3 (4.9.0-5-amd64)
- Apache 2.4.25
- OTRS 6.0.5
- GCP SQL PostgreSQL 9.6 (1 виртуальный ЦП, 3.75 ГБ памяти, 10 ГБ SSD)
Параметры тестирования
- Продолжительность: 5 минут
- Конкурентных пользователей: 100
- Объем базы: ~1000 тикетов
mpm_event (default) | mpm_prefork | |
---|---|---|
Transactions | 53033 hits | 68284 hits |
Availability | 100.00 % | 100.00 % |
Elapsed time | 299.48 secs | 299.70 secs |
Data transferred | 2365.39 MB | 3039.35 MB |
Response time | 0.54 secs | 0.41 secs |
Transaction rate | 177.08 trans/sec | 227.84 trans/sec |
Throughput | 7.90 MB/sec | 10.14 MB/sec |
Concurrency | 94.87 | 93.39 |
Successful transactions | 53033 | 68284 |
Failed transactions | 0 | 0 |
Longest transaction | 5.94 | 6.72 |
Shortest transaction | 0.18 | 0.18 |