Еще одна стенограмма доклада Переговоры Pixonic DevGAMM .
Антон Косякин — технический менеджер по продукту, работает на платформе ALICE (Jira для отелей).
Он рассказал о том, как они интегрировали в проект существующие инструменты тестирования, зачем нужны нагрузочные тесты, какие инструменты предлагает сообщество и как эти инструменты запускать в облаке.
Ниже приводится выступление и текст доклада.
Мы делаем продукт под названием ALICE Platform, и сейчас я расскажу вам, как мы решили проблему нагрузочного тестирования.
ALICE — это Jira для отелей.
Мы делаем платформу, которая поможет им разобраться в себе.
Консьерж, оператор на стойке регистрации, уборщицы – им тоже нужны билеты.
Например: звонит гость > говорит, что нужно убрать помещение > сотрудник создает заявку > ребята, которые убирают, знают, кому поручено задание > выполняют > меняют статус.
Мы b2b, поэтому цифры могут быть не впечатляющими — всего 1000 отелей, 5000 DAU. Для игр это не много, но для нас это очень круто, потому что прод серверов целых 8 и они с трудом справляются с этими 5 тысячами активных пользователей.
Так как под капотом происходит немного другое — куча баз данных, транзакций и т.д.
Самое главное: за последний год мы увеличились вдвое, теперь у нас инженерная команда около 50 человек и мы планируем удвоить базу пользователей в 2019 году.
И это главная задача, которая стоит перед нами.
Пример из жизни.
Вечером в пятницу, отработав 60-часовую рабочую неделю, в 23:00 я закончил последний звонок, быстро закончил презентацию, прыгнул в поезд и приехал сюда.
И минут пять назад я немного изменил свою презентацию.
У нас сейчас так все работает, потому что мы стартап и это круто.
Пока я ехал, часть технической команды (на производстве это называется пожар) старалась сделать так, чтобы система не зависла и при этом пользователи этого не заметили.
Им это удалось, и мы были спасены.
Как видите, по ночам мы пока спим не очень хорошо.
Мы точно знаем, что наша инфраструктура рухнет. Мы смотрим правде в глаза и понимаем ее.
Один вопрос: когда? Так мы поняли, что нагрузочное тестирование — ключ к спасению.
Это то, о чем нам нужно позаботиться.
Какие цели мы ставим перед собой? Во-первых, мы теперь должны точно понимать возможности и производительность нашей системы, насколько хорошо она работает для нынешних пользователей.
И это должно произойти до того, как пользователь разорвет с нами договор (а это может быть клиент на 150 отелей и большие деньги) из-за того, что что-то не работает или работает очень медленно.
Кроме того, у отдела продаж есть план: двукратный рост в течение следующего года.
Так уж получилось, что мы купили нашего основного конкурента и мигрируем к себе его пользователей.
И мы должны знать, что мы всё это переживём.
Знайте заранее, прежде чем придут эти пользователи и все пойдет не так.
Мы также делаем релизы.
Каждую неделю.
В понедельник.
Конечно, не во всех релизах расширяется функционал, иногда обслуживание, иногда исправление ошибок, но мы должны понимать, что пользователи этого не заметят и их опыт от этого не станет хуже.
Но мы, как хорошие разработчики, люди ленивые и не любим работать.
Поэтому мы спросили сообщество и Google, какие существуют сервисы/решения для нагрузочного тестирования.
Их было много.
Есть простейшие вещи, типа Apache Bench, который просто кикает какой-нибудь сайт по URL в сотне потоков.
Есть злая и странная версия Bees with Machine Guns, где все то же самое, но она запускает экземпляры, которые вылетают и крашат ваши приложения.
Есть JMeter, где можно написать несколько скриптов и запустить их в облаке.
Вроде бы все было хорошо, но, поразмыслив, мы поняли, что нам действительно придется сначала поработать и решить несколько задач.
Во-первых, нужно написать реальные сценарии, которые будут имитировать полную нагрузку.
В некоторых системах достаточно генерировать случайные вызовы API со случайными данными.
В нашем случае это длинные пользовательские сценарии: поступил звонок, открыл экран, ввел все данные (кто звонил, что хочет), сохранил.
Затем он появляется в мобильном приложении у другого человека, который выполнит запрос.
Не самая тривиальная задача.
И напомню, что релизы выходят каждую неделю.
Функционал обновляется, скрипты должны быть действительно актуальными.
Сначала их нужно написать, а потом поддерживать.
Но это была не самая большая проблема.
Возьмем, к примеру, Flood.io. Классный инструмент, в нем можно запускать Selenium — это когда Chrome запускается, им можно управлять, и он выполняет какие-то скрипты.
В нем вы можете запускать сценарии JMeter. Но если мы захотим запустить Selenium внутри JMeter-скриптов, внезапно все развалится, потому что ребята, которые его собирали, приняли ряд архитектурных решений.
Или, например, некоторые сервисы могут запускать JUnit — это просто и понятно, но один из этих сервисов написал свой JUnit и некоторые вещи он просто игнорирует.
Вопрос генерации нагрузки стоит остро, потому что каждый инструмент просит генерировать ее по-своему.
И даже когда удалось убедиться в адекватности скриптов, возникает вопрос: как запустить в 2-4 раза больше? Вроде как: запусти и все нормально.
Но нет. Эти запросы содержат всякие идентификаторы — мы что-то создаем, получаем новый идентификатор, меняем его по старому идентификатору, а тест, загружающий сущность по идентификатору, меняет свое поле на другое.
А 10 тестов, загружающих одну и ту же сущность по 10 раз — это не очень интересно.
Потому что вам придется загружать разные сущности по 10 раз и правильно масштабировать эту нагрузку.
Хорошо, мы хотим решить проблему нагрузочного тестирования, чтобы точно понимать, сколько пользователей будет поддерживать приложение, и чтобы наши планы сравнивались с планами отдела продаж.
Мы проанализировали решения, которые есть на рынке, а затем провели инвентаризацию наших макарон и палочек.
Поскольку релизы мы делаем каждую неделю, естественно, некоторые тесты мы автоматизировали — интеграционные и что-то еще.
Для этого мы используем огурец.
Это платформа BDD, в которой вы можете заниматься разработкой, основанной на поведении.
Те.
мы устанавливаем несколько сценариев, которые состоят из шагов.
Наша инфраструктура позволяла запускать интеграционные и функциональные тесты в двух режимах: просто пинать бэкенд, дергать API или фактически запускать Chrome через Selenium и управлять им.
Мы очень любим NewRelic. Он может просто мониторить серверы и основные показатели.
Он встроен в JVM и перехватывает все вызовы контроллеров и API конечных точек.
У них также есть решение для браузера, и поскольку большая часть нашего функционала находится там, оно тоже что-то делает в браузере и предоставляет некоторые метрики.
Соответственно, нужно все это собрать воедино.
Мы уже автоматизировали основные сценарии.
Наши скрипты (поскольку это BDD) имитируют реальных пользователей и нагрузка аналогична реальному продакшену.
В то же время мы можем масштабировать его.
Поскольку это часть процесса выпуска, он всегда поддерживается в актуальном состоянии.
Теперь возьмем любой инструмент, который сейчас есть на рынке.
Они оперируют одними и теми же примитивами: http, вызовы API через http, JSON, JUnit и всё.
Но как только мы пытаемся провести наши тесты на Cucumber, они делают то же самое, работают с теми же вещами, но ничего не работает. Мы начали думать, как справиться с этой задачей.
Небольшое отступление, потому что BDD — не слишком популярный термин в разработке игр; это больше для корпоративных решений.
Все сценарии на самом деле описывают какое-то поведение.
Формат описания сценариев очень простой: «Дано», «Когда», «Тогда» — в терминах BDD это называется «Корнишон».
Cucumber отображает это для нас в коде Java, используя аннотации и атрибуты.
Он делает то, что видит в сценарии: нам нужно дать человеку яблоко, давайте найдем способ, в котором это реализуется.
Тогда мы ввели такое понятие, как Функциональный робот. Это своего рода клиент для приложения, в нем есть методы входа пользователя, выхода из системы, создания заявки, просмотра списка заявок и т.д. И он может работать в трех режимах: с мобильным приложением, веб-приложением и просто выполнять вызовы API.
Теперь, в двух словах, то же самое и на слайдах.
Файлы функций разделены на скрипты, есть шаги и все это написано на английском языке.
Затем в игру вступает Cucumber, код Java; он отображает эти сценарии на код, который уже фактически выполнен.
Это код, который использует наше приложение.
И смотря что мы выбрали: либо через Selenium Chrome заходим в приложение ALICE.
Или то же самое через API через http.
А потом (спасибо ребятам из Яндекса за Allure Reports) нам все это прекрасно показано — сколько времени это заняло, какие тесты провалились, на каком этапе и даже прикрепили скриншот, если что-то пошло не так.
Вот краткое изложение того, что у нас уже было.
Как из этого собрать Нагрузочные тесты? У нас был Дженкинс, управляющий Cucumber Suite. Это наши тесты и они отправились в АЛИСУ.
В чем была главная проблема? Jenkins запускает тесты локально, он не может масштабироваться вечно.
Да, мы размещаемся на Amazon, в облаке, и мы можем запросить очень большую машину.
Все равно в какой-то момент мы как минимум упремся в сеть.
Нам нужно как-то разгрузить эту нагрузку.
«Спасибо Amazon», — подумал он за нас.
Мы можем упаковать наш Cucumber Suite в контейнер Docker и использовать сервис AWS (называемый Fargate), чтобы сказать: «Запустите их для нас, пожалуйста».
Проблема решена, мы можем запускать наши тесты в облаке.
Затем, поскольку мы в облаке, запускаем 5-10-20 Cucumber Suite. Но есть нюанс: при каждом прогоне всех наших функциональных тестов формируется отчет. За день мы провели 400 тестов и составили 400 отчетов.
Еще раз спасибо ребятам из Яндекса за опенсорс, мы прочитали документацию, исходники и поняли, что есть способы агрегировать все 400 отчетов в один.
Немного подправили данные, написали какие-то свои расширения и всё заработало.
Теперь от Дженкинса мы говорим «запустите нам 200 экземпляров».
Наш сценарий оркестрации отправляется на Amazon и говорит: «Запустите 400 контейнеров».
В каждом из них есть наши интеграционные тесты, они генерируют отчет, отчет собирается через Агрегатор в один кусок, закладывается в Дженкинс, применяется к заданию, работает отлично.
Но.
Я уверен, что многие из вас получали от тестировщиков странные вещи, типа «Я играл в игру, я прыгнул 10 раз, пока яростно нажимал кнопку огня и случайно нажал кнопку выключения — персонаж начал моргать, зависать» воздух, а потом компьютер выключился, разберитесь с этим.
Еще можно договориться с человеком и сказать, знаете, это невозможно воспроизвести.
Но у нас бездушные машины, они все делают очень быстро и где-то данные не загрузилось, где-то не очень быстро отрендерилось, пытаются нажать кнопку, но кнопки пока нет, или используются какие-то данные, которые еще не скачаны с сервера.
Все сворачивается и тест проваливается.
Хочу на этом акцентировать внимание) у нас есть код на Java, который запускает Chrome, который подключается через обертку в другой Java и что-то делает и при этом работает молниеносно.
Ну и очевидная проблема, вытекающая из этого: у нас 5 тысяч пользователей, но мы запустили всего 100 экземпляров наших функциональных тестов и создали одинаковую нагрузку.
Это не совсем то, чего нам хотелось, ведь мы планируем, что в следующем месяце у нас будет уже 6 тысяч пользователей.
Трудно понять такую нагрузку, понять, сколько потоков нужно запускать.
Хорошо, давайте очеловечим нашу систему.
Вот как выглядит пользовательский интерфейс:
Кто-то звонит, консьерж хочет нажать кнопку «создать новый билет», у него выскакивает окно и он должен заполнить все поля.
Но это происходит не мгновенно.
Реальный человек будет двигать мышкой, пока начнет печатать, пока что-то выберет, пока нажмет «Сохранить».
Итак, давайте замедлим наши тесты.
Мы назвали это «Человеческим режимом».
Вам просто нужно измерить, как долго длится шаг, и немного «поспать», если он был слишком быстрым.
В то же время мы можем измерить, сколько времени на самом деле занял этот шаг — если 5 минут, то здесь, вероятно, нарушен пользовательский опыт. Так как тестов у нас было довольно много, мы не стали переписывать каждый под эту штуку.
Мы взяли AspectJ, применили его к нашему коду, добавили еще 5 строк кода, отлично работает. Короткая демонстрация.
Это график запуска.
Зеленые тесты хорошие, местами плохие.
Allure покажет нам подробности, где это не удалось.
А вот график, показывающий, что у нас было много случаев.
Они проводили испытание, что-то где-то упало.
Система действительно работает — на прошлой неделе мы провели первые испытания в боевом производстве.
Теперь о следующих шагах: как, по нашему мнению, это можно улучшить.
Самое главное, мы хотим, чтобы у людей был отличный пользовательский опыт. Идея в том, что мы можем генерировать большую нагрузку на наше приложение и как бы все просто — мы просто измеряли производительность каждого запроса к серверу, продолжает ли он так же быстро отвечать или начались падения производительности (у сервера есть стали медленнее обрабатывать входящие запросы).
Но нет. В действительности клиент/приложение может отправлять на сервер сразу несколько запросов, в связке.
И ждать, пока они все будут обработаны.
И если один из запросов, самый длинный, проработал 5 секунд и продолжает работать 5 секунд, то нам совершенно не важно, как работают все остальные — так же быстро или замедленно до 4 секунд. Ведь нам еще придется ждать самые долгие, пять секунд. Или вы создали тикет, все сработало за одну миллисекунду, но тикет появился в системе слишком поздно из-за внутренних кэшей индексов.
Обычный подход не решит эту проблему, поэтому мы хотим попробовать измерить все сценарии и посмотреть, насколько на самом деле стал хуже сценарий создания билетов.
Потому что все наши сценарии основаны на вариантах использования; мы можем подражать им, начав с одного человека на стойке регистрации и 10 уборщиц.
Потом 20 или 30 уборщиков.
Но фронт людей все тот же.
Те.
мы можем генерировать реальную нагрузку на основе моделей поведения, очень близкую к реальной нагрузке.
Также многорегиональное тестирование.
Наша система используется во всем мире (хотя все хостится в Америке) и поэтому мы можем генерировать нагрузку как из России, так и из Америки, чтобы посмотреть, какая из них начнет тормозить быстрее.
Вопросы из зала
— Вы вынуждены писать большое количество логики и когда что-то немного меняется, в ваших функциональных тестах многое ломается.Получается, что на поддержку тестов вы тратите едва ли не больше времени, чем на разработку? - Да, но нет. Это BDD, это не совсем функциональные тесты, они ближе к интеграционным тестам.
И что бы мы ни меняли, сценарий все равно остается прежним.
Нажимаю кнопку, вижу окно, в нем ввожу номер зала, откуда пришел запрос, имя человека и дату, на которую нужно забронировать столик.
Если разметка изменилась, поля поменялись местами, если в бэкенде что-то происходит по-другому, тест сохраняется, потому что мы на очень высоком уровне, нажимаем кнопки в браузере.
Поэтому мы защищены от большого количества изменений.
Бывают моменты, когда все может развалиться.
Поэтому в процедуре релиза те ребята, которые пишут новую функцию, отвечают за то, чтобы увидеть, что что-то сломано, и исправить это.
Но пока таких проблем было не так много.
— Бывали ли у вас ситуации, когда после одного изменения все тесты краснели? - Не было.
Теоретически такое могло бы произойти, если бы в скрипте была не кнопка, а какой-то другой способ открыть окно для ввода данных о билете.
Но, как я показал ранее, все наши сценарии состоят из шагов.
Шаги — это множество вещей, и если у нас есть 100 скриптов, которые нажимают на одну и ту же кнопку, шаг остается тем же самым.
И если из-за этого конкретного шага все пошло не так, мы это исправляем, переписываем, и все тесты сразу становятся зелеными.
Хотя однажды, когда мы случайно что-то сломали, с нами случилось такое.
Зеленых осталось всего 40%, хотя до этого было 99%.
Это было одно маленькое изменение.
Мы исправили один шаг (строку кода) и все снова стало зеленым.
— Ваши тесты хоть и не являются интеграционными, но и не совсем функциональны.
Так или иначе, это своего рода графический интерфейс, где нажимаются кнопки и происходит какое-то взаимодействие конкретно с внешней оболочкой.
Я так понимаю, у вас тесты в таком виде, вы просто запускаете много потоков одновременно.
Чем не нравятся запросы, которые генерируются стандартными инструментами: JMeter, Gatling, которые никак не взаимодействуют с внешней оболочкой, а просто отправляют запросы на сервер? - Все очень просто.
Какова архитектура нашего приложения? У нас есть бэкэнд, есть фронтенд. Фронтенд — это веб.
Есть мобильное приложение.
И когда я создаю тикет, мой фронтенд тоже подключается, например, к серверам событий.
Я создаю билет на бэкенде и все люди, которые сидят в этом же отеле, смотрят билеты в этом же отеле, им приходит сообщение от серверов событий: ребята, обновитесь, данные изменились.
И чтобы все собрать воедино, у нас есть одна точка — клиент. Он подключается к большому количеству разных компонентов, и нам приходится либо вручную программировать, чтобы мы создали билет в бэкенде, а затем подключаемся к серверу событий, регистрируемся на нем и ждем от него каких-то событий.
Или мы просто запустили браузер, в котором уже все собрано, этот код уже написан и мы делаем все так, как нам нужно.
- Но это разные подходы? Либо работаем конкретно с сервером, либо с окном.
Вы можете моделировать запросы сразу к нескольким серверам.
«Поэтому я вам и говорил, что у нас есть функциональные роботы, которые вызываются из тестов.
Есть те, кто берет Chrome и выполняет push-уведомления высокого уровня.
Есть те, кто не нажимает кнопку, ничего не происходит, но в момент создания тикета он отправляет запрос на сервер, и мы можем запустить то или это.
Мы решили работать через Chrome по одной простой причине — мы хотим имитировать реальных пользователей, то, как они на самом деле его используют. Пока загружалась его страница, пока все рендерилось, пока обрабатывались Java-скрипты и так далее.
Мы хотим быть как можно ближе к пользователю, и это действительно Интернет. — Но многое будет зависеть от того, какой интернет у пользователя, какая среда.
Но конкретная работа приложения будет зависеть от вас и с вашей стороны.
Вопрос в том, что мы тестируем: всё в принципе или какую-то часть отдельно? — Хороший вопрос, поэтому я и говорил о мультирегиональном тестировании.
Мы можем попытаться генерировать трафик из Мексики, где интернет может быть не очень хорошим.
Мы можем генерировать трафик из Америки, которая находится очень близко к региону Амазонки, где все размещено.
Но если человек на заднем плане открыл YouTube или начал добывать биткойны, то мы не сможем это воспроизвести.
Здесь вам придется дождаться звонка от реальных клиентов и зайти к ним, чтобы разобраться в чем дело.
Это не серебряная пуля, да.
- Вы развертываете тесты.
У вас есть какая-то Selenium Grid или что-то в этом роде? Вы также делаете их мультирегиональными.
— Огурцов просто много: всё компилируется в JAR, JAR упаковывается в Docker-образ и мы говорим Фаргейту, запускай этот образ в контейнере.
А флуд.ио запустил сетку из Selenium и доступа к ней не было, поэтому наши тесты не сработали.
— Насколько широка ваша полигон? Вы упомянули, что у вас есть Chrome, что на вашем телефоне есть приложение.
А если я запущу Internet Explorer 4 (если где-нибудь накопаю), то он может вылететь? Либо под какой-то очень специфической версией Android, либо еще что-то.
— К счастью, это предприятие.
И у предприятия есть одна очень интересная вещь, а именно требования.
Плюс мы, конечно, схитрили — наш мобильник — гибридное приложение, оно тоже выходит на бэкенд, просто веб-просмотр.
Поэтому, если Android умеет запускать веб-просмотр и у него нормальный функционал, особых проблем с этим нет. — Я слушал, где ты тестируешь, куда забиваешь Нагрузочную нагрузку? Прямо в производство?
— Откройте слайд.
Есть среда и раскрывающийся список.
И мы исключили оттуда производство.
Там была интересная история, когда это был еще не Load, а просто автоматизация.
Там вы ввели собственный четырехбуквенный URL-адрес для перехода, а затем добавили aliceapp.com. Затем мы провели нагрузочные тесты, и это было удалено, потому что мы случайно вышли из пре-продакшена.
Дело не в том, что он просто ушёл на 504, а вообще не вернулся, потому что репликация MySQL рухнула и синхронизация с ElasticSearch развалилась.
— Если вы не фокусируетесь на производстве (и это хорошо), как вы тогда понимаете, что на производстве будет происходить ровно то же самое? Очевидно, вы не поднимаете точно такой же объем экземпляров.
— Наша среда загрузки настроена идентично производственной среде, и у нас есть процедура ежедневной загрузки дампа из производственной базы данных в среду.
Те.
мы имитируем копию.
— Вы его все время держите, на испытаниях не поднимаете? - Нет, не знаем.
Мы стартап, в пятницу все, кроме производства, отключается, а в понедельник включается по требованию.
— Правильно ли я понял, что ваши тесты имитируют поведение пользователя и заполняют поля, т.е.
нажимают кнопки прямо в html или делают запросы методом API? — Браузер открывается и Selenium позволяет получить прямой доступ к DOM-модели этого браузера: тяните любые события, можно сказать в поле ввода, вот событие key down прошло, но нажмите на это.
И мы оперируем именно этими терминами.
- Кто пишет тесты? Разработчики, тестировщики? — На данный момент существует специальная команда.
Сначала ничего не было, мы мучились.
Потом появился КК, мы стали меньше страдать, КК пострадал.
Они составили список дымовых тестов и своего рода контрольный список.
Потом мы пришли к ним и сказали: «дайте мне ваш чек-лист, мы его автоматизируем».
Следующий шаг — заставить разработчиков писать эти тесты при разработке нового функционала, потому что инфраструктура есть, все фреймворки есть, осталось только реализовать нажатие кнопок и прочие подобные вещи.
Больше выступлений от Pixonic DevGAMM Talks
- Использование Consul для масштабирования сервисов с отслеживанием состояния (Иван Бубнов, DevOps в BIT.GAMES);
- CICD: плавное развертывание в распределенных кластерных системах без простоев (Егор Панов, системный администратор Pixonic);
- Попрактикуйтесь в использовании модели актера на серверной платформе игры Quake Champions. (Роман Рогозин, бэкенд-разработчик Sabre Interactive);
- Мета-серверная архитектура мобильного онлайн-шутера Tacticool (Павел Платто, ведущий инженер-программист PanzerDog);
- Как ECS, C# Job System и SRP меняют подход к архитектуре (Валентин Симонов, полевой инженер Unity);
- Принцип KISS в разработке (Константин Гладышев, ведущий игровой программист 1С Game Studios);
- Общая логика игры на клиенте и сервере (Антон Григорьев, заместитель технического директора Pixonic).
-
Управляйте Клиентами С Помощью Act! В Облаке
19 Oct, 24 -
Мечта Слонов
19 Oct, 24 -
New.bwc.ru Глазами Артемия Лебедева
19 Oct, 24