Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Алексей Рагозин, Артём Панасюк — Распределённое...

Moscow JUG
January 20, 2016

Алексей Рагозин, Артём Панасюк — Распределённое нагрузочное тестирование на Java

Основной принцип PTDD (performance test driven development) — начинать регулярное нагрузочное тестирование, как только появляется код, который можно тестировать. Зачастую это означает, что инфраструктура распределённого нагрузочного тестирования должна появляться раньше самого приложения и эволюционировать с его развитием. Это делает непрактичным использование традиционных деплоймент тулов (chef, ansible, и т.п.).

Предлагаемое решение задачи — полный стек автоматизации распределённого нагрузочного тестирования на Java.

В докладе:
• Почему инструментом выбрана Java и в чём преимущества "монокультурного" подхода.
• "9 fallacities of distributed computing" с точки зрения распределённых тестов.
• От императивной Явы, к массивно-параллельной императивной Яве.
• Фреймворк: архитектура, компоненты, использование.

Фреймворк находится в свободном доступе и распространяется под лицензией Apache 2.0

Moscow JUG

January 20, 2016
Tweet

More Decks by Moscow JUG

Other Decks in Programming

Transcript

  1. В докладе • Введение • Концепция PTDD Performance Test Driven

    Development • Распределённый нагрузочный тест – что это? • Стек инструментов • Пример теста
  2. Performance Test Driven Development • Пишем неоптимизированный код • Пишем

    нагрузочные тесты / бенчмарк • Исправляем проблемы производительности • Организуем изолированные тесты в профили нагрузки по мере добавления функционала • Непрерывное тестирование производительности
  3. Как тестировать до “начала”? Нет скрипов, инфраструктуры, приложения Надо тестировать

    базовые сценарии Тестировать на реальном масштабе Тестировать сценарии отказов Дизайн меняется на ходу, тесты вместе с ним Тесты должны гонять себя сами, у разработчиков хватает работы.
  4. Как тестировать до “начала”? На чём вы пишите юнит-тесты? •

    JUnit - Java Почему бы не писать нагрузочные также? • Мы знаем Java • На Java есть библиотеки для всего • Никаких переформанс инженеров тесты пишут разработчики
  5. Вопрос культуры “Классический” подход • bash + ssh + анализ

    логов + Excel / R • Мало пригоден для повторного использования • Короткий период полураспада тестов • Использование незнакомого инструментария “Монокультурный” подход • Платформа приложения = платформа автоматизации − Приходится изобретать велосипеды, но + Решается проблема культурного диссонанса
  6. Нагрузочный тест Развёртывание  В распределённой среде Подготовка данных /

    разогрев Сценарий тестирования  Например, дневной профиль нагрузки с отказом узла в кластера Сбор метрик  Тестовые события  Метрики ОС  Данные профилирования Подготовка отчёта
  7. Стек инструментов Nanocloud - https://github.com/gridkit/nanocloud/  Развертывание / управление распределённой

    средой GridBeans – “массивно параллельная” Java  Оркестрация развертывая и подготовки  Выполнение сценария Nimble  Компоненты: cбор данных, мониторинг и прочее Отчёты  Сырой CSV на выходе, решение не найдено
  8. 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; } }); }
  9. 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
  10. Master – slave communications Master process Slave host SSH (Single

    TCP) Slave Slave RMI (TCP) std err std out std in diag Slave controller Slave controller multiplexed slave streams Agent
  11. 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
  12. 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
  13. Распределённый сценарий • Простые шаги (реализованные на Java) • Выполняемые

    в распределённой системе согласно сценарию • Возможность синхронизации шагов • Обмен данными между шагами • Нет циклов и условного выполнения • Fail fast – ошибка любого шага завершает сценарий
  14. 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(); }
  15. Mockito way 1. Декларация намерений  Моки и вызовы методов

     “Виртуальное” время  “Абстрактная” распределённость 2. Физическое выполнение  Привязка к топологии  Зависимости между шагами  Параллельное / распределённое выполнение
  16. Простой пример #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"); }
  17. Простой пример #1 deploy reader reader .configure() start reader .execute()

    done deploy writer writer .configure() writer .execute()
  18. Простой пример #1 Драйвер  Интерфейс декларирующий шаги  Шаги

    – методы  Шаг может вернуть “интерфейс”  Шаги могут принимать параметры  Сериализуемые объекты  Результаты выполнения шагов  Реализация драйвера размещается в распределённой среде используя локатор
  19. Простой пример #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 Перемотка времени
  20. Простой пример #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()
  21. Простой пример #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");
  22. Простой пример #2 deploy reader reader .configure() start wallclock .delay()

    done reader .createTask() exec .execute() stop readTask readJob .stop() readJob readJob .join()
  23. Простой пример #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"); Вспомогательный сервис Интерфейс фоновых задач Получение сервиса
  24. Простой пример #2 Ошибка выполнение шага отлавливается и завершает сценарий.

    Когда создаётся фоновая задача, используется Activity.join() шага, который не завершится пока задача не будет остановлена. Wallclock – драйвер предоставляемый из коробки. ExecutionDriver – пример вспомогательного драйвера.
  25. Распределённый сценарий Всех аспекты теста – Развёртывание / Сбор данных

    / Мониторинг / и т.д. шаги / драйверы единого сценария
  26. Распределённый сценарий 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.
  27. Метеринг Сбор метрик в распределённой среде  Данные тестовых событий

     Данные мониторинга Метрики аккумулируются на локальном диске и передаются на управляющий узел по завершении сценария Все результаты экспортируются в CSV файл большой CSV файл
  28. Мониторинг Метрики OS - https://github.com/hyperic/sigar  Network interface stats 

    Process stats (поиск нужных процессов) JVM  GC  Threads  Custom MBeans Build your own
  29. Профилирование BTrace 2 - https://github.com/jbachorik/btrace2  Инструментирующий профайлер  Точки

    перехвата на Java  Развёртывание как часть сценария  Интеграция с метерингом
  30. Ссылки 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