Performance of Performance Testing tools
Минулого року я брав участь в конференції QA Fest 2019 та презентував свої дослідження з порівняння додатків для тестування навантаження. Моєю метою було підготувати середовище та виконати однакові набори тестів для Locust, Gatling та JMeter, порівняти, наскільки релевантні їх результати та скільки ресурсів їм треба для роботи. Хто хоче, може подивитись відео доповіді:
Чому я вибрав саме ці 3 тули проміж десятків інших? Мої основні критерії:
- Є безкоштовним
- Має велику спільноту і нормальну документацію
- Може генерувати навантаження в 10 000 користувачів
- Підтримує без болі та страждань транзакційність (дані з одного респонсу веб серверу можуть бути використані в наступному реквесті)
Тож я провів тести, записав результати і презентував їх. Але сам лишився не дуже задоволений проведеною роботою — JMeter згенерував безліч помилок в процесі роботи, результати тестів для всіх тулів відрізнялись і взагалі — майже за рік оновились версії ОС та фреймворків — чому б не провести роботу над помилками тести ще кілька разів?
Мета
Я хочу провести однакові тести навантаження одного й того самого серверу в одних і тих самих умовах і перевірити, наскільки будуть відрізнятись результати тесту та ресурси, що потрібні тулам для роботи. Щоб при нагоді точно розуміти, чим можна користуватись, які можуть будти підводні камені та чиїм результатам можна довіряти.Setup
Для початку давайте пробіжимося, як встановити та налаштувати ПЗ для тестування навантаження, оскільки я мав кілька нюансів, на вирішення яких я витратив кілька зайвих годин часу.Locust
Власне, нічого дуже складного у встановленні немає — інструкція є в офіційній документації Locust: Треба мати Python version 3.6+ і виконати наступну команду в консолі:pip install locustАле виявилось, у Windows 10 та з python 3.8 не все так просто. Якщо спробувати встановити, вам буде показано помилку і пропозицію встановити MS C++ в пакеті Visual Studio Build Tools (виявляється, деякі модулі Locust написані на C++ та компілюються на вашому ПК для пришвидшення швидкодії). Записав окреме відео про це
Gatling
Передумовами для встановлення є:- Java 8+
- Scala 2.12 (саме така версія)
- Apache Maven (опціонально)
- Gatling binaries
Але мені більше подобається, коли є підсвітка синтаксису, підказки та автодоповнення коду. Тому вирішив написати гайд, як запускати тести в IntelliJ IDEA:
JMeter
Певне, найпопулярніша програма для тестування навантаження. Не має ніяких підводних каменів. Треба мати Java 8+ та, власне, завантажити JMeter. І можна користуватись.Що тестувати?
В якості «жертви» я вирішив написати малий веб сервер з усього одним REST endpoint’ом — який буде повертати строку hello world на GET запит. Веб сервер розгорнув в докері на домашньому NAS. Сам сервер написав (якщо так можна сказати) на python, використовуючи фреймворк Flask. Розгорнув сервер за допомоги Gunicorn + nginx.Весь код сервера:
from flask import Flask, escape, request, send_file app = Flask(__name__) @app.route('/') def hello(): name = request.args.get("name", "World") return f'Hello, {escape(name)}!' @app.route('/access.log') def access_log(): return send_file('access.log', cache_timeout=-1)
Уважні читачі можуть помітити, що в коді 2 ендпоінта — другий я додав, щоб виводити access.log і перевіряти, чи справді всі мої запити досягли серверу.
Докер файл:
FROM python:3.7-alpine COPY perf_target.py /app/perf_target.py WORKDIR /app RUN pip install --upgrade pip && pip install flask gunicorn EXPOSE 8888 CMD gunicorn -w 4 -b 0.0.0.0:8888 --access-logfile access.log perf_target:app
Test Configuration
Найменш гнучка частина моїх тестів — конфігурація системи, на якій я буду генерувати навантаження. Але від неї залежить якість моїх тестів та релевантність результатів (крім того, як я вже писав раніше, я оновив «залізо», ОС та всі програми до останніх версій і можу додатково порівняти, як сильно це вплинуло).Test PC:
- CPU AMD Ryzen 7 4800H 2.9 Ghz
- RAM 16 Gb
- Windows 10 2004 Pro x64
- Java 8
- Scala 2.12
- Python 3.8
- CPU Intel Celeron J1900 2 Ghz
- RAM 8 Gb
- Flask WS in Docker python:3.7-alpine 4 Gb RAM
- 100 Mbps (за найповільнішою ланкою в моїй домашній мережі)
Додаткова передумова, до якої я прийшов пізніше, і яка змусила мене переробити тести — додати значення в реєстр Windows, що дозволяє ОС збільшити ліміт мережевих підключень. Без нього «важкі» тести ламаються через неможливість створити мережеве з’єднання:
Name: MaxUserPort Type: DWORD Value: 65534 decimal Path: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Тестові сценарії
Ідея тестів проста — навантаження лінійно зростає протягом Ramp time, потім тест має видавати однакове навантаження, протягом якого треба зібрати метрики серверу (throughput, середній та медіанний час відповіді) та клієнту (CPU, RAM, threads).Також вирішив записати проходження всіх тестів, щоб потім можна було проаналізувати їх перебіг та результати.
Код тестів
Locustfrom locust import HttpUser, task, between class WebsiteUser(HttpUser): host = 'http://192.168.2.136:8888/' wait_time = between(1, 2) @task def posts(self): self.client.get("/")Gatling
package Sample import io.gatling.core.Predef._ import io.gatling.http.Predef._ import scala.concurrent.duration._ class MaxPerformance extends Simulation { val httpProtocol = http .baseUrl("http://nas:8888") val scn = scenario("max performance") .forever(exec(http("simple get") .get("/")) .pause(1 second, 2 seconds)) setUp(scn.inject(rampUsers(10000) during (20 seconds), nothingFor(2 minutes))) .pauses(normalPausesWithStdDevDuration(2 seconds)) .maxDuration(180 seconds).protocols(httpProtocol) }
JMeter
І щоб уникнути непорозумінь — запускав тест я з консолі, як радить офіційна документація:
jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder]
Test #1
Моя початкова ідея — виконати «важкий тест», що зможе нагрузити як сервер, так і систему, на якій я виконую тест. Обрав наступні параметри:- 10 000 users
- 1 GET request
- Expected result — HTTP 200 OK
- пауза між викликами
1-2 sec - Ramp time — 20 sec — лінійне зростання навантаження
- Час тесту — 3 min
Тести проведено, метрики зібрано:
Metric | Locust | JMeter | Gatling |
Throughput (RPS) | 533 | 475 | 794 |
Average response time, sec | 10.5 | 15.6 | 9.8 |
Median response time, sec | 13 | 21 | 10 |
Test PC RAM, Gb | 0.8 | 2.3 | 1.5 |
Test PC Threads | 14 | 10056 | 117 |
Total requests | 114 882 | 100 797 | 142 997 |
Success rate, % | 100 | 36 | 29 |
Які висновки та нотатки я зробив:
- Без зміни в реєстрі Windows всі 3 тести мають невеликий Success rate — тобто багато запитів навіть не були створені і не змогли навантажити сервер
- Заміри CPU клієнта більше плутають. Я вимірював їх за допомоги тулів perfmon та procexp. Перший показував завантаження 100%, другий — до 10%. В Інтернеті кажуть, що різниця може бути в методі підрахунку (враховуючи system idle чи ні) та кількості ядер. Якщо хтось знає, в чому причина — напишіть, думаю, багатьом цікаво!
- Якщо ви шукаєте в таблиці метрики CPU та RAM сервера — їх там немає, оскільки моя мета була протестувати тули, а не сервер — я нехтую цими метриками
- Locust повільніше за всіх створює 10 000 користувачів. Я встановив швидкість у 500 користувачів на секунду, але знадобилась приблизно хвилина, щоб створити всіх
- При цьому Locust потребує найменше ресурсів та не має жодної помилки — на всі 114 з гаком тисяч запитів отримав HTTP 200 OK
- В тестах JMeter та Gatling майже всі помилки — request timeout
- JMeter має найпростішу реалізацію, у порівнянні з іншими (шо потребує значних ресурсів) — як бачите, 10 000 користувачів — 10 000 паралельних потоків
- Чисто з цікавості запускав тест JMeter в графічному режимі — отримав ті самі результати, лише в процесі роботи він використовував на 1 ГБ оперативної пам’яті більше.
- Результати тесту Gatling не корелюють з результатами інших тулів (по кількості запитів та RPS)
- Результати тестів показали, що мій сервер має точку насичення у приблизно 500 запитів на секунду — при подальшому зростанні навантаження росте лише час відповіді
Test #2
Після першого тесту я вирішив провести ще одну серію тестів «полегше», що перевірити поведінку тулів та їх результати. Дані тесту:- 500 users
- 1 GET request
- Expected result — HTTP 200 OK
- пауза між викликами
1-2 sec - Ramp time — 10 sec — лінійне зростання навантаження
- Час тесту — 2 min
Metric | Locust | JMeter | Gatling |
Throughput (RPS) | 330 | 235 | 269 |
Average response time, ms | 30 | 50 | 27 |
Median response time, ms | 14 | 6 | 10 |
Test PC RAM, Mb | 59 | 1 280 | 1 252 |
Test PC Threads | 14 | 528 | 84 |
Total requests | 36 731 | 27 805 | 32 335 |
Success rate, % | 100 | 100 | 100 |
Нотатки:
- Незважаючи на те, що за однаковий час всі тули зробили приблизно однакову кількість запитів, я отримав різні результати Throughput та response time. Припускаю, що результати залежать від методу підрахунку а також від швидкості роботи HTTP клієнтів тулів
Висновки і плани
Чисто суб’єктивно, мені серед усіх тулів більше за все подобається працювати з Locust (люблю python). Також приємними бонусами є швидкість роботи та невелика кількість ресурсів, необхідна для роботи.JMeter — класика, проста і зрозуміла, і необхідна у випадках, коли треба тестувати не HTTP протоколи :)
Найменше мені сподобався Gatling — що не зміг продемонструвати в моїх досить специфічних тестах ані економії ресурсів, ні більш менш релевантних результатів. Більш того, для його роботи необхідно мати одну специфічну версію Scala (і, знову ж таки суб’єктивно, мені не сподобався принцип написання тестів Gatling у вигляді ланцюгів викликів)
Об’єктивно: під кожну задачу треба правильно обирати тул та схему навантаження. Не кожен може давати велику потужність з одного ПК — можна скористатись можливістю розподіленого навантаження (JMeter та Locust можуть). Під час написання статті знайшов дослідження JMeter з оптимальної кількості юзерів
Всім, кому цікаво, можуть взяти код і спробувати провести свої тести — проект на Github. Якщо маєте рекомендації чи побажання — пишіть в коментарях.
У мене ще є нереалізовані ідеї, про які я хочу написати пізніше, якщо вам цікаво:
- Перевірити, як працюють мої тести в wsl2 — я вже намагався їх запускати в минулому і ОС просто зависала. Якщо результати будуть позитивними — провести тести з Yandex-tank (його дуже хвалили в коментах до моїх попередніх статей) та tsung
- Розробники Locust додали в новій версії новий fast http клієнт. І мені дуже кортить дізнатись, наскільки він швидший за звичайний (python requests)
А ще ми з колегами ведемо телеграм канал про тестування t.me/qamania — заходьте, ми намагаємось щодня писати щось цікаве про нашу професію
29 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів