Введение
Данная статья ориентирована в первую очередь на технических специалистов, из области обеспечения качества и производительности программных продуктов. В статье подробно представлена информация о возможностях высокопроизводительного варианта логирования Apache JMeter в базу Oracle. Разработка использовалась в боевых условиях на проектах нагрузочного тестирования, которые проводились сотрудниками компании ООО «Перфоманс Лаб».
Представленное решение позволяет обеспечить централизованное хранение результатов нагрузочных тестов, в которых используется JMeter, а так же значительно сократить время на обработку и анализ результатов тестирования.
Для инженера теперь будет доступен весь функционал СУБД Oracle для работы с данными.
Возможности
Разработанный комплекс средств, предназначенный для Apache JMeter, позволяет выполнять логирование результатов теста (транзакции, время отклика, ответ сервера, время выполнения операции) в БД Oracle в режиме реального времени.
Для чего это нужно
Описанный подход обработки данных позволяет автоматизировать сбор и обработку данных при частом проведении нагрузочных тестов с использованием Apache JMeter.
В случае, когда время на обработку результатов теста сильно ограничено и объем логов достаточно большой, данное средство позволяет быстро формировать отчеты о результатах работы операций (количество, время отклика, т.д.) в виде таблиц или графиков. Время на обработку логов за несколько часовой тест составляет несколько секунд – выполнение запроса SQL.
Для обработки результатов можно использовать весь возможный функционал СУБД Oracle, тем самым получая самую разную структуру отчета, на любой вкус.
Достоинства
— Высокая скорость обработки логов с теста;
— Данные за все проведенные тесты находятся в одном месте – БД;
— Удобство при подготовке отчетов – задается диапазон, за который требуется сформировать статистику, и выполняется SQL-запрос;
— Гибкость обработки логов – возможности ограничиваются только функционалом Oracle и фантазией тестировщика;
— Высокая скорость логирования из-за отсутствия блокировок (на доступ в БД) при работе большого количества VU, так как запись выполняется только одним потоком (по умолчанию).
Недостатки
— Требуется разворачивание СУБД Oracle, мощности сервера зависят от планируемого профиля нагрузки;
— Первоначальная разработка шаблонов SQL-запросов требует определенного времени;
— В тест-план Jmeter’а необходимо добавлять BeanShell Listener и следить за уровнем вложенности транзакций (подробнее в разделе «Запись в общую очередь»);
— Обработка результатов во время теста может привести к увеличению времени записи логов в БД (все зависит от мощностей БД и наличия индексов).
Схема работы системы логирования
Логика проста:
— В начале теста запускается поток, который создает одно соединение (по умолчанию) с БД;
— Логи записываются в общую очередь;
— Есть поток синхронизации, который периодически скидывает содержимое очереди в БД.
Тест план для логирования должен содержать две дополнительные потоковые группы (Создание коннектов и Синхронизация логов). Для того, чтобы результат выполнения сэмпла попадал в общую очередь необходимо в «Рабочей группе» добавить BeanShell Listener, содержимое которого будет рассмотрено ниже.
При запуске теста однократно выполняется подключение к БД, после чего каждую секунду (интервал можно настраивать) поток синхронизации проверяет наличие данных в очереди и записывает их в БД. Запись в БД осуществляется параллельно с работой основной нагрузки, значительного влияния на нее при этом не оказывается.
Шаблон тест-плана из приложения (скачать его можно здесь) рекомендуется использовать в качестве стандартной конфигурации (файл «db_logger_plan.jmx»).
Подключение к БД
Для подключения к базе необходимо указать: хост, порт, сид, логин, пароль, кол-во потоков (лучше пока использовать = 1, название таблицы в БД.
Например, строки выглядят так:
import ru.perflab.jmeter.OracleDBLogger;
OracleDBLogger.INSTANCE.connect(«127.0.0.1», 1521, «xe», «sa», «gfhjkm», 1, «jm_log_table»);
Синхронизация
Вызов синхронизации приводит к тому, что данные из очереди записываются в БД (используются PreparedStatement и AddBatch). Для вызова достаточно указать строки:
import ru.perflab.jmeter.OracleDBLogger;
ResponseCode = new String(«count=»+OracleDBLogger.INSTANCE.insert());
Оптимальный интервал запуска – 1 секунда.
Запись в общую очередь
Очередь состоит из HashMap’ов, для того, чтобы добавить элемент, необходимо добавить в тест план BeanShell Listener с содержимым:
import java.util.HashMap;
import ru.perflab.jmeter.OracleDBLogger;
HashMap p = new HashMap();
p.put(«Timestamp», new java.sql.Timestamp(prev.getTimeStamp()));
p.put(«CurrentTimestamp»,new java.sql.Timestamp(prev.currentTimeInMillis()));
p.put(«Time», prev.getTime());
p.put(«Latency», prev.getLatency());
p.put(«IdleTime», prev.getIdleTime());
p.put(«Bytes», prev.getBytes());
p.put(«SampleCount», prev.getSampleCount());
p.put(«isSuccessful», prev.isSuccessful());
p.put(«SampleLabel», prev.getSampleLabel());
p.put(«Hostname», sampleEvent.getHostname());
p.put(«ThreadName», prev.getThreadName());
p.put(«AllThreads», prev.getAllThreads());
p.put(«UrlAsString», prev.getUrlAsString());
p.put(«Request», new String(prev.getDataEncodingWithDefault()));
p.put(«ResponseData», new String(prev.getResponseData()));
p.put(«DataType», prev.getDataType());
OracleDBLogger.INSTANCE.put(p);
Смотрим тест-план в приложении (файл «db_logger_plan.jmx»).
Весь список параметров является обязательным, если что-либо передавать не нужно, то указываются пустые значения, но лучше ничего не менять.
ВАЖНО! Иногда требуется записывать в БД показатели не самого сэмпла а его родителя, тогда добавяются «prev.getParent()», например, prev.getParent().getDataType(). Такое может понадобиться, когда вложенные запросы, например, HTTP. Для группировки подзапросов можно попробовать использовать Transaction или Simple Controller.
Распаковка БД
Для системы подойдет, как вариант Oracle XE, так и Enterprise (лучше второй вариант). Мощности сервера зависят от интенсивности эмулируемой нагрузки (количество сэмплов в секунду), тестирование проводилось на проекте в «боевых условиях», где нагрузка составляла около 450 транзакций (сэмплов) в секунду. БД имела характеристики: 4*Power7(64bit) SMT-4, RAM 12 Гб, утилизация CPU составляла ~15%, памяти тоже было достаточно.
Скрипт для создания таблицы
Создаем таблицу в БД с нужными триггерами и последовательностями:
CREATE TABLE JM_LOG_TABLE
(
«T_ID» NUMBER(38,0) NOT NULL ENABLE,
«TIME_STAMP» TIMESTAMP (7), --Параметер prev.getTimeStamp() (время запуска сэмпла)
«JM_DATE» TIMESTAMP (7),-- Параметер prev.currentTimeInMillis() (локальное время нагр. станции, когда лог был записан в очередь)
«DB_TIME_STAMP» TIMESTAMP (7),--Время БД, когда лог был записан в таблицу
«ELAPSED_TIME» NUMBER(38,0),--Время отклика (мс)
«LATENCY» NUMBER(38,0),
«IDLE_TIME» NUMBER(38,0),
«BYTE_COUNT» NUMBER(38,0),
«SAMPLE_COUNT» NUMBER(10,0),
«SUCCESS» NUMBER(1,0),
«LABEL» VARCHAR2(1024 BYTE),
«HOSTNAME» VARCHAR2(200 BYTE),
«THREAD_NAME» VARCHAR2(200 BYTE),
«THREAD_COUNTS» NUMBER(38,0),
«URL» VARCHAR2(2048 BYTE),
«REQUEST_MSG» BLOB,--Предполагается, что запрос к серверу, но не нашлось как получить данный параметр в JM, всегда можно подправить листенер
«RESPONSE_MSG» BLOB,--Заполняется только, если была ошибка
«DATA_TYPE» VARCHAR2(200 BYTE) --Бесполезная штука — тип ответа сервера
);
create sequence jm_log_table_t_id_seq start with 1 increment by 1;
CREATE OR REPLACE TRIGGER JM_LOG_TABLE_T_ID_INSERT before
INSERT ON jm_log_table FOR EACH row DECLARE
BEGIN
SELECT jm_log_table_t_id_seq.nextval,sysdate INTO :new.t_id, :new.db_time_stamp FROM dual;
END;
/
--Индексы добавляются по необходимости, чтобы не возникало проблем при перестройке, когда идет большой поток логов.
CREATE INDEX JM_LOG_TABLE_JM_DATE ON JM_LOG_TABLE(JM_DATE);
Результаты
Чтобы собрать статистику за тест нужно выполнить SQL-запрос, который предварительно надо подготовить. Например, этим можно заняться пока идет тест. Огромный плюс данного подхода в том, что новые запросы нужно создавать достаточно редко, так как формат данных, необходимых в отчете, почти не меняется в ходе проекта. Примеры запросов в приложении к статье (папка «SQL_Requests_for_DB_Logger»).
Формат данных на выходе
В итоге, выполнение запросов в БД приводит к формированию таблички, примерно следующего вида:
По подобной таблице можно построить примерно такой график:
Производительность
Реальная производительность системы будет зависеть от размера тест-плана, железа нагрузочной станции, железа сервера БД и канала связи.
На данный момент максимум зафиксировать не удалось, так как на ноутбуке нагрузочной станции не хватило памяти (под рукой был только с 2Гб). В реальном проекте возможности определить потолок тоже не было, поэтому было зафиксировано, что 1000 сэмплов в секунду логируются без проблем (для тестов больше не надо было).
Условия. Тест «логера» проводился на двух ноутбуках:
Нагр. Станция — Lenovo v360 (Pentium 2*P6100 2000 Mhz, Ram 2Gb); под JMeter v 2.8 выделено 512 MB, Win 7.
БД Oracle (XE 11g) – Lenovo Y550P (CPU Core i7 8*1.66 Ghz, Ram 4 Gb), Win XP. Для таблицы был построен только 1 индекс (jm_date).
Сеть – 1 Гигабит через кросс-кабель.
Максимум сколько удалось выжать из нагрузочной станции — 1800 сэмплов в секунду, после чего JMeter выдал Out of memory и «остановился».
Тест-план содержал Dummy Sampler с задержкой 500 мс, кол-во тредов 1000.
На рисунке выше представлен график транзакций (сэмплов)/в секунду. Видно, что проблемы с производительностью нагрузочной станции (не достаточная мощность ноутбука) появились при интенсивности запросов в 1800 сэмплов в секунду, что уже очень неплохо.
Загрузка системных ресурсов на БД:
• ЦП 10-15%,
• свободная память 1 Гб (25%),
• утилизация дисков 5-10%,
• сеть < 1%.
На нагрузочной станции:
• ЦП 30%,
• память кончилась («съел» JMeter и ОС).
Для проверки надежности разработки проведен тест на 700 тредах и длительностью 2 часа, производительность составляла 1400 сэмплов в секунду.
На рисунке представлен график транзакций в секунду (агрегация 1 sec), как видно нагрузка работала стабильно в ходе всего теста, и функционал логирования не оказал влияния на основные запросы JMeter’a.
Стабильность разработки подтверждается графиком выше, на котором видно, что время записи логов (1400 записей за каждую секунду) в базу не превышало 600 мс (розовая линия).
Время работы сэмплеров, эмулирующих нагрузку (Dummy Sampler) соответствовало указанным в тест-плане 500 мс, за исключением редких отклонений.
В данном тесте мощности ноутбуков было достаточно для работы базы и JMeter.
Загрузка системных ресурсов на БД:
• ЦП 10%,
• свободная память 1 Гб,
• утилизация дисков 5-7%,
• сеть < 1%.
На нагрузочной станции:
• ЦП 30%,
• свободная память ~25%.
Заключение
В данной статье представлен один из возможных вариантов централизованного хранения результатов многочисленных load (нагрузочных) тестов с использованием средства нагрузки Apache Jmeter и СУБД Oracle.
Бесчисленное множество файлов (csv, xml) с логами JMeter от проводимых тестов могут быть заменены одной базой данных, где результаты надежно хранятся и могут быть доступны для всех участников проекта нагрузочного тестирования.
Предлагаемое решение легко внедряется в уже имеющийся тест-план (две дополнительные «тред-гуппы» и листенер), не требует значительных вычислительных мощностей для БД и позволяет гибко и удобно проводить обработку, анализ результатов тестов.
Внедрив данную разработку в свой проект, можно отлично экономить время при анализе результатов для более интересных дел, как, например, общение с друзьями, чай/кофе, ну или что кому по душе…
В следующей статье
Будет описана разработка на основе MS Excel, при помощи которой, подключаясь к базе, можно формировать таблицы с результатами тестов и графики, используя ODBC DataSource операционной системы.
Файл Excel содержит VBA-макрос, который подключается к базе и выполняет SQL-запрос для выборки результатов тестов в таблицу Excel, из которой автоматически строятся необходимые графики.
Эта разработка оказалась отличным дополнением к описанному в данной статье «логеру», ведь обработка результатов каждого нового теста занимает всего несколько секунд.
Автор: p_lab