Главная » Хабрахабр » Управление мощностями: в поисках идеального баланса

Управление мощностями: в поисках идеального баланса

Меня зовут Иван Давыдов, я занимаюсь исследованиями производительности в Яндекс.Деньгах. Здравствуйте!

Если последних не очень много, они не мешают друг другу работать — им комфортно и уютно. Представьте, что у вас есть мощные сервера, на каждом из которых размещается ряд приложений. Однажды вы приходите к микросервисам и выносите часть «тяжелой» функциональности в отдельные приложения.

В итоге на каждом сервере станет «кучковаться» десяток приложений, которые борются за общие ресурсы. Здесь можно увлечься, и микросервисов станет слишком много, вследствие чего станет сложно управлять ими и обеспечивать их отказоустойчивость. Получится «большая семья», а в большой семье клювом не щёлкай!

Моя история будет о тяжелых и бессонных ночах, когда я сидел под лампой в ночи и обстреливал прод. Однажды мы тоже с этим столкнулись. Всё началось с того, что мы стали замечать на боевых серверах проблемы, связанные с сетью.

Параллельно выяснилось, что такие же ошибки возникают и при обычном пользовательском потоке, но в гораздо меньшем объеме. Они сильно влияли на производительность и вносили ощутимые просадки.

Такое бывает, когда все имеющиеся на серверах сокеты постоянно открываются и закрываются. Проблема скрывалась в утилизации TCP-сокетов более чем на 100%. Из-за этого возникают сетевые проблемы взаимодействия между приложениями и появляются разного рода ошибки – недоступен удаленный хост, разорвано HTTP/HTTPS соединение (connection/read timeout, SSL peer shut down incorrectly) и другие.

Так мы пришли к двум выводам – нужно оценить, как используются текущие мощности, и изолировать приложения друг от друга. Даже если у вас нет своего сервиса электронных платежей, оценить масштаб боли во время какой-нибудь очередной распродажи не сильно сложно – трафик увеличивается в несколько раз, а деградация производительности может привести к значительным убыткам.

Для этого мы использовали гипервизор, который содержит множество отдельных контейнеров с приложениями. Чтобы изолировать приложения, мы решили прибегнуть к контейнеризации. Это позволяет изолировать ресурсы процессора, памяти, устройств ввода/вывода, сети, а также деревья процессов, пользователей, файловые системы и так далее.

Это красивое и элегантное решение, но перед этим необходимо ответить на ряд вопросов: При таком подходе каждое приложение имеет свое окружение, что обеспечивает гибкость, изолированность, надежность, и повышает общую производительность системы.

  • Какой запас по производительности имеет один инстанс приложения на текущий момент?
  • Как масштабируется приложение и есть ли избыточность по ресурсам в текущей конфигурации?
  • Возможно ли повысить производительность одного инстанса и что является «узким местом»?

С такими вопросами коллеги пришли к нам – команде исследователей производительности.

Чем мы занимаемся?

Каждый бизнес-процесс, будь то оплата товара в магазине кошельком или перевод денег между пользователями, по сути, представляет для нас цепочку запросов в системе. Мы делаем всё для обеспечения производительности нашего сервиса и, в первую очередь, исследуем и улучшаем её для бизнес-процессов нашего продакшена.

Отчёты содержат метрики производительности и подробное описание выявленных проблем и узких мест. Мы проводим эксперименты и составляем отчеты, чтобы оценить производительность системы при высокой интенсивности входящих запросов. С помощью этой информации мы улучшаем и оптимизируем нашу систему.

Оценка потенциала каждого приложения осложняется тем, что в организации последовательности запросов бизнес-процесса участвуют несколько микросервисов, использующих мощности всех задействованных инстансов.

Поэтому, в дополнение к текущим исследованиям, необходимо проводить оценку используемых ресурсов в рамках процесса управления мощностями. Выражаясь метафорически, мы знаем мощь нашей армии, но не знаем потенциала каждого из бойцов. Этот процесс называется «Capacity management».

В рамках такого процесса отслеживается актуальная производительность приложений (как медианная, так и максимальная) и предоставляются данные о текущем запасе. Наши исследования помогают выявлять и предотвращать нехватку ресурсов, прогнозировать закупки железа и иметь точные данные о текущих и потенциальных возможностях системы.

Суть управления мощностями – в поиске баланса между потребляемыми ресурсами и производительностью.

Плюсы:

  • В любой момент известно, что происходит с производительностью каждого приложения.
  • Меньше рисков при добавлении новых микросервисов.
  • Меньше затрат на закупки нового оборудования.
  • Те мощности, что уже есть, используются более разумно.

Мы провели исследование, целью которого была оценка того, как используются мощности на продакшн-серверах. Вернемся к нашей ситуации со множеством приложений.

Вкратце план действий такой:

  1. Определить пользовательскую интенсивность на конкретных приложениях.
  2. Составить профиль стрельбы.
  3. Оценить производительность каждого инстанса приложения.
  4. Оценить масштабируемость.
  5. Составить отчеты и заключения о минимально необходимом количестве инстансов для каждого приложения в боевой среде.

А теперь подробнее.

Инструменты

Для визуализации собранных метрик используется Grafana. Для сбора метрик пользовательской интенсивности мы используем Heka и Zabbix.

Heka предоставляет данные по количеству и времени выполнения входящих/исходящих запросов, сбор метрик по внутренним очередям приложений и ещё бесконечное количество других данных. Zabbix нужен для наблюдения за ресурсами серверов, такими как: CPU, Memory, Network connections, DB и другими. Мы – не исключение. Grafana – гибкий инструмент для визуализации, который используют разные команды Яндекс.Денег.


Grafana умеет показывать, например, такие вещи

С его помощью составляется сценарий стрельбы, который включает реализацию запросов, мониторинг валидности ответа, гибкое управление подаваемого потока и многое другое. В качестве генератора трафика используется Apache JMeter. Данный инструмент имеет как свои плюсы, так и минусы, но углубляться «почему именно данный продукт?» я не буду.

Он позволяет подключать свои модули для получения любых нужных функций и выводить результаты в консоли или в виде графиков. В дополнение к JMeter используется фреймворк yandex-tank – инструмент для нагрузочного тестирования и анализа производительности веб-сервисов и приложений. В графане тоже можно настраивать дискретность, но данное решение является более затратным по физическим и логическим ресурсам. Результаты наших стрельб отображаются в Лунапарке (аналог https://overload.yandex.net), где мы можем за ними подробно наблюдать в реальном времени, вплоть до секундных пиков, обеспечивая необходимую и достаточную дискретность, и тем самым более оперативно реагировать на всплески, возникающие при стрельбе. Но только – тссс! А иногда мы даже выгружаем сырые данные и визуализируем их через GUI Jmeter.

Практически любые сбои, возникающие в приложении под большим потоком трафика, оперативно анализируются с помощью Kibana. Кстати, о деградации. Но это тоже не панацея – некоторые сетевые проблемы можно проанализировать только посредством снятия и анализа трафика.

За единицу измерения решили взять суммарное процессорное время выполнения запросов, то есть учитывались количество запросов и время их выполнения. С помощью Grafana мы проанализировали пользовательскую интенсивность в приложении за несколько месяцев. Именно этот список и лег в основу профиля стрельбы. Так мы составили список самых «тяжелых» запросов, которые составляют большую часть потока на приложение.


Пользовательская интенсивность на приложение за несколько месяцев

Профиль стрельбы и пристрелка

Профиль составляется из двух частей. Мы называем стрельбой запуск сценария в рамках проводимого эксперимента.

При реализации необходимо проанализировать пользовательскую интенсивность на каждый входящий запрос приложения и сделать процентное соотношение между ними, чтобы выявить топ самых вызываемых и долго выполняемых. Первая часть – составление сценария запросов. Вторая часть – подбор параметров роста потока: с какой интенсивностью и как долго подавать нагрузку.

Для большей наглядности методику составления профиля лучше продемонстрировать на примере.

На основе данного распределения и времени ответа по каждому из запросов составляются группы в JMeter, каждая из которых является независимым генератором трафика. В Grafana строится график, который отражает пользовательскую интенсивность и долю каждого запроса в общем потоке. В основу сценария ложатся только самые «тяжелые» запросы, так как реализовать все (в некоторых приложениях их более сотни) затруднительно, да это и не всегда требуется из-за их сравнительно низкой интенсивности.


Процентное соотношение запросов

В данном исследовании рассматривается пользовательская интенсивность на постоянном потоке, а периодически возникающие «всплески» чаще всего рассматриваются в частном порядке.

В первую группу вошли «request 1» и «request 2» в соотношении 1 к 2. В нашем примере рассматривается две группы. Остальные запросы компонента имеют гораздо меньшую интенсивность, поэтому мы не включаем их в сценарий. Аналогично во вторую группу вошли запросы 3 и 4.


Распределение запросов по группам в Jmeter

Исходя из медианного времени ответа по каждой из групп, производится оценка производительности по формуле:

x = 1000 / t, где t – медианное время, мс

Получаем результат вычисления и оцениваем приблизительную интенсивность при увеличении числа потоков:

TPS = x * p, где p – количество потоков, TPS – transaction per second, а x – это результат предыдущего вычисления.

Исходя из полученных результатов можно подобрать первоначальные параметры роста. Если запрос обрабатывается за 500 мс, то при одном потоке мы имеем 2 Tps, а при 100 потоках в идеале должны иметь 200 Tps. После первых итераций исследований эти параметры обычно корректируются.

Это делается для того, чтобы проверить работоспособность сценария при постоянном потоке, оценить время ответа на запросы в каждой из групп и получить процентное соотношение по запросам. Когда сценарий стрельбы готов, мы запускаем пристрелку – стрельбу на одну минуту в один поток.

Поэтому мы выставили одинаковую скорость роста потока для обеих групп. При прогоне такого профиля мы выяснили, что при одинаковой интенсивности процентное соотношение запросов сохраняется, так как среднее время ответа во второй группе больше, чем в первой. В иных случаях пришлось бы экспериментальным путем подбирать параметры для каждой группы по отдельности.

В этом примере интенсивность подавалась ступенчато, то есть добавлялось некоторое число потоков за определенный интервал.


Параметры роста интенсивности

Параметры роста интенсивности были такими:

  • Целевое количество потоков – 100 (определяется при пристрелке).
  • Рост в течение 1000 секунд (~16 мин.).
  • 100 ступеней.

Интервал между добавлением потоков и количество добавляемых потоков варьируются в зависимости от поведения системы на конкретном шаге. Таким образом, каждые 10 секунд мы добавляем по одному потоку. Зачастую интенсивность подается с плавным ростом, чтобы можно было отслеживать состояние системы на каждой из ступеней.

Боевые стрельбы

В это время пользовательский трафик минимален – это значит, что стрельба почти не повлияет на пользователей, и погрешность в результатах будет меньше. Обычно стрельба запускается ночью с удаленных серверов.

После всех корректировок запускается повторная стрельба в один инстанс. По результатам первых стрельб в один инстанс корректируем количество потоков и время роста, анализируем поведение системы в целом и находим отклонения в работе. На этом этапе мы определяем максимальную производительность и отслеживаем использование аппаратных ресурсов как сервера с приложением, так и всего, что за ним стоит.

При этом был зафиксирован рост времени ответа по всем запросам без увеличения производительности, то есть мы достигли насыщения, но не деградации. По результатам стрельбы, производительность одного инстанса нашего приложения составила порядка 1000 Tps.

Это важно, так как железо может отличаться, а значит, разные инстансы могут давать сильно разные показатели. На следующем этапе сравниваем результаты, полученные с других инстансов. Поэтому мы выделили группу серверов с лучшими результатами и исследовали масштабируемость на них. Так было и у нас – часть серверов оказалась на порядок производительнее в силу поколения и характеристик.


Сравнение производительности серверов

Масштабируемость и поиск узких мест

В теории производительность должна расти линейно с увеличением количества инстансов. Следующий шаг – исследовать производительность на 2, 3 и 4 инстансах. На практике обычно всё не так.

В нашем примере получился практически идеальный вариант.

Это решается управлением размером пулов на исходящей и входящей стороне и приводит к увеличению производительности приложения. Причиной насыщения роста производительности являлось исчерпание пулов коннекторов до последующего бэкенда.

Эксперименты показали, что вместе с производительностью сильно растет утилизация CPU и коннектов баз данных. В других исследованиях мы столкнулись с более интересными вещами. БД оказалась не готова к такому объему. В нашем случае это произошло из-за того, что в конфигурации с одним инстансом мы упирались в собственные настройки пулов приложения, а при двух инстансах увеличили это количество вдвое, тем самым удвоив исходящий поток. И такие результаты мы получили уже при двух инстансах! Из-за этого стали забиваться пулы к БД, процент потребляемого CPU добрался до критической отметки в 99%, и увеличивалось время обработки запросов, а часть трафика вообще отваливалась.

Результаты оказались приблизительно такими же, как и при первых двух, разве что быстрее пришли к разладке. Чтобы окончательно убедиться в своих опасениях, мы провели стрельбу в 3 инстанса.

Тут может быть все, что угодно, начиная с запросов к БД, которые выполняются минутами, заканчивая кодом, который нерационально использует память Java-машины. Есть еще один пример «затыков», который, на мой взгляд, является самым болезненным – это плохо написанный код.

Итоги

В результате у исследуемого в нашем примере инстанса приложения запас по производительности оказался более чем в 5 раз.

Достаточно двух инстансов для конкретного приложения, а использование всех 15, которые есть в наличии, избыточно. Для увеличения производительности необходимо рассчитать достаточное количество пулов обработчика в настройках приложения.

После исследования получены следующие результаты:

  • Определена и поставлена на мониторинг пользовательская интенсивность за 1 месяц.
  • Выявлен запас по производительности одного инстанса приложения.
  • Получены результаты об ошибках, возникающих под большим потоком.
  • Выявлены узкие места для дальнейшей работы над увеличением производительности.
  • Выявлено минимально достаточное количество инстансов для корректной работы приложения. И, как следствие, выявлена избыточность использования мощностей.

Теперь мы можем точно сказать, сколько контейнеров и с какими характеристиками необходимо иметь, как рационально использовать их мощности и над чем стоит поработать, чтобы обеспечивать производительность на должном уровне. Результаты исследования легли в основу проекта по переводу компонентов в контейнеры, о котором мы расскажем в следующих статьях.

Заходите в наш уютный телеграм-чатик, где вы всегда можете попросить совета, помочь коллегам и просто пообщаться тему исследований производительности.

Задавайте вопросы в комментариях и подписывайтесь на блог Яндекс.Денег – скоро мы расскажем о фишинге и как на него не попадаться. На сегодня всё.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Steal: кто крадёт у виртуалок процессорное время

Хочу рассказать простым языком о механике возникновения steal внутри виртуальных машин и о некоторых неочевидных артефактах, которые нам удалось выяснить при его исследовании, в которое мне пришлось погрузиться как техдиру облачной платформы Mail.ru Cloud Solutions. Привет! Платформа работает на KVM. ...

Почему бессмысленно писать прогнозы

Сейчас в различных СМИ да и на Хабре публикуется большое количество прогнозов о бурном развитии робототехники, беспилотных автомобилей и альтернативной энергетики. Люди зачастую настроены излишне оптимистично, и ожидают какого-то рывка. Я предлагаю посмотреть, что прогнозировали на Хабре, и каким видели ...