Распределённое нагрузочное
тестирование на Java
Алексей Рагозин
Артём Панасюк
jug.msk.ru 2016
В докладе
• Введение
• Концепция PTDD
Performance Test Driven Development
• Распределённыйнагрузочныйтест–чтоэто?
• Стек инструментов
• Пример теста
Тестирование
– инструмент познания мира
PerformanceTestDrivenDevelopment
Функциональное тестирование
Нагрузочное тестирование
Cost of bug
Test volume
Release
Release
Test volumeCost of bug
PerformanceTestDrivenDevelopment
• Пишем неоптимизированный код
• Пишем нагрузочные тесты / бенчмарк
• Исправляем проблемы производительности
• Организуем изолированные тесты в профили
нагрузки по мере добавления функционала
• Непрерывное тестирование производительности
Как тестировать до “начала”?
Нет скрипов, инфраструктуры, приложения
Надо тестировать базовые сценарии
Тестировать на реальном масштабе
Тестировать сценарии отказов
Дизайн меняется на ходу, тесты вместе с ним
Тесты должны гонять себя сами, у
разработчиков хватает работы.
Как тестировать до “начала”?
На чём вы пишите юнит-тесты?
• 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.underdebuger)
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");
}
Локатор
Драйвер прокси
CheckpointCheckpoint
Перемотка времени
Простой пример #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
alexey.ragozin@gmail.com
http://blog.ragozin.info
- my articles
http://www.meetup.com/bigmoscow
- community events in Moscow

Распределённое нагрузочное тестирование на Java

  • 1.
    Распределённое нагрузочное тестирование наJava Алексей Рагозин Артём Панасюк jug.msk.ru 2016
  • 2.
    В докладе • Введение •Концепция PTDD Performance Test Driven Development • Распределённыйнагрузочныйтест–чтоэто? • Стек инструментов • Пример теста
  • 3.
  • 4.
  • 5.
    PerformanceTestDrivenDevelopment • Пишем неоптимизированныйкод • Пишем нагрузочные тесты / бенчмарк • Исправляем проблемы производительности • Организуем изолированные тесты в профили нагрузки по мере добавления функционала • Непрерывное тестирование производительности
  • 6.
    Как тестировать до“начала”? Нет скрипов, инфраструктуры, приложения Надо тестировать базовые сценарии Тестировать на реальном масштабе Тестировать сценарии отказов Дизайн меняется на ходу, тесты вместе с ним Тесты должны гонять себя сами, у разработчиков хватает работы.
  • 7.
    Как тестировать до“начала”? На чём вы пишите юнит-тесты? • JUnit - Java Почему бы не писать нагрузочные также? • Мы знаем Java • На Java есть библиотеки для всего • Никаких переформанс инженеров тесты пишут разработчики
  • 8.
    Вопрос культуры “Классический” подход •bash + ssh + анализ логов + Excel / R • Мало пригоден для повторного использования • Короткий период полураспада тестов • Использование незнакомого инструментария “Монокультурный” подход • Платформаприложения=платформаавтоматизации − Приходится изобретать велосипеды, но + Решается проблема культурного диссонанса
  • 9.
    Нагрузочный тест Развёртывание  Враспределённой среде Подготовка данных / разогрев Сценарий тестирования  Например,дневнойпрофильнагрузкисотказомузлавкластера Сбор метрик  Тестовые события  Метрики ОС  Данные профилирования Подготовка отчёта
  • 10.
    Стек инструментов Nanocloud -https://github.com/gridkit/nanocloud/  Развертывание / управление распределённой средой GridBeans – “массивно параллельная” Java  Оркестрация развертывая и подготовки  Выполнение сценария Nimble  Компоненты: cбор данных, мониторинг и прочее Отчёты  Сырой CSV на выходе, решение не найдено
  • 11.
  • 12.
    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; } }); }
  • 13.
    All you needis … NanoCloud requirements  SSHd  Java (1.6 and above) present  Works though NAT and firewalls  Works on Amazon EC2  Works everywhere where SSH works
  • 14.
    Master – slavecommunications 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
  • 15.
    Death clock isticking Master JVM kills slave processes, unless  SSH session was interrupted  someone kill -9 master JVM  master JVM has crashed (e.g.underdebuger) Death clock is ticking on slave though  if master is not responding  slave process will terminate itself
  • 16.
    Cloud scale JVM SameAPI – 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
  • 17.
  • 18.
    Распределённый сценарий • Простыешаги (реализованные на Java) • Выполняемые в распределённой системе согласно сценарию • Возможность синхронизации шагов • Обмен данными между шагами • Нет циклов и условного выполнения • Fail fast – ошибка любого шага завершает сценарий
  • 19.
    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(); }
  • 20.
    Mockito way 1. Декларациянамерений  Моки и вызовы методов  “Виртуальное” время  “Абстрактная” распределённость 2. Физическое выполнение  Привязка к топологии  Зависимости между шагами  Параллельное / распределённое выполнение
  • 21.
    Простой пример #1 publicvoid 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"); }
  • 22.
  • 23.
    Простой пример #1 Драйвер Интерфейс декларирующий шаги  Шаги – методы  Шаг может вернуть “интерфейс”  Шаги могут принимать параметры  Сериализуемые объекты  Результаты выполнения шагов  Реализация драйвера размещается в распределённой среде используя локатор
  • 24.
    Простой пример #1 publicvoid 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"); } Локатор Драйвер прокси CheckpointCheckpoint Перемотка времени
  • 25.
  • 26.
    Простой пример #2 MyReaderreader = 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");
  • 27.
  • 28.
    Простой пример #2 MyReaderreader = 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"); Вспомогательный сервис Интерфейс фоновых задач Получение сервиса
  • 29.
    Простой пример #2 Ошибкавыполнение шага отлавливается и завершает сценарий. Когда создаётся фоновая задача, используется Activity.join() шага, который не завершится пока задача не будет остановлена. Wallclock – драйвер предоставляемый из коробки. ExecutionDriver – пример вспомогательного драйвера.
  • 30.
    Распределённый сценарий Всех аспектытеста – Развёртывание / Сбор данных / Мониторинг / и т.д. шаги / драйверы единого сценария
  • 31.
    Распределённый сценарий Fallacies ofdistributed 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.
  • 32.
  • 33.
    Метеринг Сбор метрик враспределённой среде  Данные тестовых событий  Данные мониторинга Метрики аккумулируются на локальном диске и передаются на управляющий узел по завершении сценария Все результаты экспортируются в CSV файл большой CSV файл
  • 34.
    Мониторинг Метрики OS -https://github.com/hyperic/sigar  Network interface stats  Process stats (поиск нужных процессов) JVM  GC  Threads  Custom MBeans Build your own
  • 35.
    Профилирование BTrace 2 -https://github.com/jbachorik/btrace2  Инструментирующий профайлер  Точки перехвата на Java  Развёртывание как часть сценария  Интеграция с метерингом
  • 36.
    Ссылки 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
  • 37.
    Thank you Alexey Ragozin alexey.ragozin@gmail.com http://blog.ragozin.info -my articles http://www.meetup.com/bigmoscow - community events in Moscow