Upload
aragozin
View
1.069
Download
9
Embed Size (px)
Citation preview
Распределённое нагрузочное тестирование на Java
Алексей Рагозин
Артём Панасюк
jug.msk.ru 2016
В докладе
• Введение
• Концепция PTDD Performance Test Driven Development
• Распределённый нагрузочный тест – что это?
• Стек инструментов
• Пример теста
Тестирование – инструмент познания мира
Performance Test Driven Development
Функциональное тестирование
Нагрузочное тестирование
Cost of bug
Test volume
Release
Release
Test volumeCost of bug
Performance Test Driven Development
• Пишем неоптимизированный код • Пишем нагрузочные тесты / бенчмарк • Исправляем проблемы производительности • Организуем изолированные тесты в профили
нагрузки по мере добавления функционала • Непрерывное тестирование производительности
Как тестировать до “начала”?
Нет скрипов, инфраструктуры, приложения
Надо тестировать базовые сценарии
Тестировать на реальном масштабе
Тестировать сценарии отказов
Дизайн меняется на ходу, тесты вместе с ним
Тесты должны гонять себя сами, у разработчиков хватает работы.
Как тестировать до “начала”?
На чём вы пишите юнит-тесты? • JUnit - Java
Почему бы не писать нагрузочные также? • Мы знаем Java • На Java есть библиотеки для всего • Никаких переформанс инженеров
тесты пишут разработчики
Вопрос культуры
“Классический” подход • bash + ssh + анализ логов + Excel / R • Мало пригоден для повторного использования • Короткий период полураспада тестов • Использование незнакомого инструментария
“Монокультурный” подход • Платформа приложения = платформа автоматизации − Приходится изобретать велосипеды, но + Решается проблема культурного диссонанса
Нагрузочный тест
Развёртывание В распределённой среде
Подготовка данных / разогрев
Сценарий тестирования Например, дневной профиль нагрузки с отказом узла в кластера
Сбор метрик Тестовые события Метрики ОС Данные профилирования
Подготовка отчёта
Стек инструментов
Nanocloud - https://github.com/gridkit/nanocloud/
Развертывание / управление распределённой средой
GridBeans – “массивно параллельная” Java
Оркестрация развертывая и подготовки
Выполнение сценария
Nimble
Компоненты: cбор данных, мониторинг и прочее
Отчёты
Сырой CSV на выходе, решение не найдено
Nanocloud
Nanocloud
Удалённое выполнения Java кода
Просто как …
@Test
public void hello_remote_world() {
Cloud cloud = CloudFactory.createSimpleSshCloud();
cloud.node("myserver.acme.com").exec(new Callable<Void>(){
@Override
public Void call() throws Exception {
String localhost = InetAddress.getLocalHost().toString();
System.out.println("Hi! I'm running on " + localhost);
return null;
}
});
}
All you need is …
NanoCloud requirements
SSHd
Java (1.6 and above) present
Works though NAT and firewalls
Works on Amazon EC2
Works everywhere where SSH works
Master – slave communications
Master process Slave hostSSH
(Single TCP)
Slave
Slave
RMI
(TCP)
std err
std out
std in
diag
Slave
controller
Slave
controller
multiplexed slave streams Agent
Death clock is ticking
Master JVM kills slave processes, unless
SSH session was interrupted
someone kill -9 master JVM
master JVM has crashed (e.g. under debuger)
Death clock is ticking on slave though
if master is not responding
slave process will terminate itself
Cloud scale JVM
Same API – different topoligies
in-process (debug), local, remote (distributed)
Transparent remoting
SSH to manage remote server
Automatic classpath replication (with caching)
Zero infrastructure
Any OS for master host
SSHd + JVM for slave hosts (Unix / Cygwin)
200+ slave topology in routinely used
Распределённый сценарий
Распределённый сценарий
• Простые шаги (реализованные на Java)
• Выполняемые в распределённой системе согласно сценарию
• Возможность синхронизации шагов
• Обмен данными между шагами
• Нет циклов и условного выполнения
• Fail fast – ошибка любого шага завершает сценарий
Mockito
@Test public void test() { MyList mock = Mockito.mock(MyList.class, Mockito.RETURNS_DEEP_STUBS); Mockito.when(mock.get(0).getValue()).thenReturn("v1"); Mockito.when(mock.get(1).getValue()).thenReturn("v2"); Assert.assertEquals(null, mock.get(2).getValue()); Assert.assertEquals("v2", mock.get(1).getValue()); Assert.assertEquals("v1", mock.get(0).getValue()); InOrder io = Mockito.inOrder(mock); io.verify(mock).get(2); io.verify(mock).get(1); io.verify(mock).get(0); io.verifyNoMoreInteractions(); }
Mockito way
1. Декларация намерений
Моки и вызовы методов
“Виртуальное” время
“Абстрактная” распределённость
2. Физическое выполнение
Привязка к топологии
Зависимости между шагами
Параллельное / распределённое выполнение
Простой пример #1
public void example() { MonadBuilder bld = MonadFactory.build(); MyReader reader = bld.locator(Cloud.class).at("reader") .deploy(MyReader.class, ...); reader.configure("read config"); bld.join("start"); reader.execute(); bld.join("done"); bld.rewind(); MyWriter writer = bld.locator(Cloud.class) .at("writer").deploy(MyWriter.class, ...); writer.configure("write config"); bld.join("start"); writer.execute(); bld.join("done"); }
Простой пример #1
deploy
reader
reader
.configure()
start
reader
.execute()
done
deploy
writer
writer
.configure()
writer
.execute()
Простой пример #1
Драйвер Интерфейс декларирующий шаги Шаги – методы Шаг может вернуть “интерфейс” Шаги могут принимать параметры Сериализуемые объекты Результаты выполнения шагов
Реализация драйвера размещается в распределённой среде используя локатор
Простой пример #1
public void example() { MonadBuilder bld = MonadFactory.build(); MyReader reader = bld.locator(Cloud.class).at("reader") .deploy(MyReader.class, ...); reader.configure("read config"); bld.join("start"); reader.execute(); bld.join("done"); bld.rewind(); MyWriter writer = bld.locator(Cloud.class).at("writer") .deploy(MyWriter.class, ...); writer.configure("write config"); bld.join("start"); writer.execute(); bld.join("done"); }
Локатор Драйвер прокси
Checkpoint Checkpoint
Перемотка времени
Простой пример #1
deploy
reader
reader
.configure()
start
reader
.execute()
done
deploy
writer
writer
.configure()
writer
.execute()
deploy
reader
reader
.configure()
reader
.execute()
deploy
writer
writer
.configure()
writer
.execute()
Простой пример #2
MyReader reader = bld.locator(Cloud.class).at("reader") .deploy(MyReader.class, ...); reader.configure("read config"); bld.sync(); Runnable readTask = reader.createTask(); bld.join("start"); ExecutionDriver exec = bld.bean(ExecutionDriver.class); Activity readJob = exec.execute(readTask); bld.join("stop"); readJob.stop(); bld.join(readJob); bld.join("done"); bld.rewind("start"); bld.wallclock().delay(30, TimeUnit.SECONDS); bld.join("stop");
Простой пример #2
deploy
reader
reader
.configure()
start
wallclock
.delay()
done
reader
.createTask()
exec
.execute()
stop
readTask
readJob
.stop()
readJob
readJob
.join()
Простой пример #2
MyReader reader = bld.locator(Cloud.class).at("reader") .deploy(MyReader.class, ...); reader.configure("read config"); bld.sync(); Runnable readTask = reader.createTask(); bld.join("start"); ExecutionDriver exec = bld.bean(ExecutionDriver.class); Activity readJob = exec.execute(readTask); bld.join("stop"); readJob.stop(); bld.join(readJob); bld.join("done"); bld.rewind("start"); bld.wallclock().delay(30, TimeUnit.SECONDS); bld.join("stop");
Вспомогательный сервис
Интерфейс фоновых задач
Получение сервиса
Простой пример #2
Ошибка выполнение шага отлавливается и завершает сценарий.
Когда создаётся фоновая задача, используется Activity.join() шага, который не завершится пока задача не будет остановлена.
Wallclock – драйвер предоставляемый из коробки.
ExecutionDriver – пример вспомогательного драйвера.
Распределённый сценарий
Всех аспекты теста – Развёртывание / Сбор данных / Мониторинг / и т.д.
шаги / драйверы единого сценария
Распределённый сценарий
Fallacies of distributed computing https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
• The network is reliable – fail test fast.
• Latency is zero – small number of round trip.
• Bandwidth is infinite – low bandwidth control flow.
• The network is secure – irrelevant for testing.
• Topology doesn't change – fail test fast and rerun.
• There is one administrator – zero deployment.
• Transport cost is zero – there is no free lunch
• The network is homogeneous – location conscious scenario.
Вспомогательные компоненты
Метеринг
Сбор метрик в распределённой среде
Данные тестовых событий Данные мониторинга
Метрики аккумулируются на локальном диске и передаются на управляющий узел по завершении сценария
Все результаты экспортируются в CSV файл большой CSV файл
Мониторинг
Метрики OS - https://github.com/hyperic/sigar Network interface stats Process stats (поиск нужных процессов)
JVM GC Threads Custom MBeans
Build your own
Профилирование
BTrace 2 - https://github.com/jbachorik/btrace2
Инструментирующий профайлер
Точки перехвата на Java
Развёртывание как часть сценария
Интеграция с метерингом
Ссылки
NanoCloud • https://github.com/gridkit/nanocloud/
• https://code.google.com/p/gridkit/wiki/NanoCloudTutorial
• Maven Central: org.gridkit.lab:nanocloud:0.8.10
• http://blog.ragozin.info/2013/01/remote-code-execution-in-java-made.html
GridBeans • https://github.com/aragozin/gridbeans
Nimble • https://github.com/gridkit/nimble
Пример бенчмарка • https://github.com/gridkit/zk-benchmark-example
Thank you
Alexey Ragozin [email protected]
http://blog.ragozin.info - my articles http://www.meetup.com/bigmoscow - community events in Moscow