Блог
Инженерия Автор
15.01.2021

Производительность распределенного хранилища: препродакшен тесты

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

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

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

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

Задачи

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

Подготовка

Клиенты

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

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

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

Лимиты

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

На хранилище может быть установлено два типа лимитов:

  1. Лимиты на количество операций (IOPS).
  2. Лимиты на количество переданных данных (MB/s).

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

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

Набор тестов

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

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

Мы отталкиваемся от предположения, что наиболее требовательный к задержкам клиент будет работать с диском синхронно. Значит, что на каждую операцию записи будет поступать операция синхронизации кеша(flush). И только дождавшись завершения такой операции, клиентское ПО будет считать запись успешной. Так работают, например, классические базы данных с журналом.

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

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

Запись и чтение тестируются разными размерами блока — 4КиБ и 4МиБ. Маленький размер блока позволяет нагрузить кластер большим количеством операций, а большой — объемом передаваемых данных. Так мы проверяем его работу в двух крайностях. Можно добавлять и промежуточные варианты размеров блока, так как различное ПО оперирует разным размером блока.

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

Статистика

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

Минимальный набор метрик предоставляется любыми современными системами сбора статистики с операционной системы из коробки, такими как node-exporter, collectd и тп. В деталях же, эта тема требует отдельной проработки, так как чтобы понимать какие дополнительные метрики необходимо собирать именно вам для дальнейшего анализа, зависит от конкретной системы и особенностей её эксплуатации. Если на текущем этапе вы не имеете представления о том, какие метрики могут понадобиться, то нужно потратить время на изучение системы и особенностей её работы. Общий подход здесь может быть — собирайте всё, что можете собрать с минимальными трудозатратами.

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

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

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

Окружение

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

Пример того, что нужно собрать:

  1. Версия операционной системы.
  2. Версия ядра.
  3. Версия используемых драйверов.
  4. Версия софта хранилища.
  5. Модель, количество и частота процессоров.
  6. Модель, количество, объем и частота оперативной памяти.
  7. Модель материнской платы.
  8. Модель сетевых карт и сетевая топология.
  9. Модель и количество дисков.
  10. Количество хостов в кластере.
  11. Количество гипервизоров.
  12. Количество и характеристики виртуальных машин.

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

Тестирование

Пустой кластер

Нужно убедиться, что сейчас нагрузки на кластер и гипервизоры нет и не будет, кроме той, что генерируется во время теста. Это важный шаг, и если им пренебречь, в лучшем случае обнаружится, что во время тестов происходило что-то, что повлияло на результаты и придется всё переделывать, а в худшем — это выяснится уже после запуска кластера в продакшен и результаты лучше всего будет выкинуть, так как их интерпретация уже будет усложнена.

Такая проверка нужна перед запуском каждого теста.

Заполнение

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

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

Первый тест

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

Оценка задержки

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

Выбор эталонной глубины очереди

Для запуска масштабного тестирования нужно подготовить “максимально эффективного” клиента. Это такой клиент, который работает на пике доступной производительности диска. Если не брать в расчет загруженность кластера, то доступная клиенту производительность диска зависит от двух показателей:

  1. скорость обработки каждой операции;
  2. количество параллельно выполняемых операций.

С точки зрения клиента мы не можем повлиять на скорость обработки конкретных операций, но можем увеличивать параллелизм. Следовательно, максимально эффективный клиент, это тот клиент, который использует максимальный параллелизм при работе с диском, при этом укладывается в доступные ему ресурсы (IOPS / MB/s). Это значит, что для поиска такого клиента нам нужно запускать каждый тест из набора с разной глубиной очереди. В результате мы получим информацию о том, на какой глубине очереди каждый из тестов работает наиболее эффективно.

По результатам тестов нужно строить графики, показывающие распределение латенси и IOPS. Нужно будет найти такую глубину очереди, при которой распределение задержки ещё не растет, при этом показатели IOPS или MB/s уже находятся максимально близко к заданному лимиту. Максимальная эффективная глубина очереди для тестов с разными параметрами может отличаться. Берём её за эталон для тестов и используем на следующем этапе. Это и есть наши самые эффективные клиенты.

Тестирование кластера

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

По результатам нужно дать оценку для каждого теста:

  1. Максимальное количество максимально эффективных клиентов до деградации производительности кластера.
  2. Скорость деградации производительности при дальнейшем росте количества клиентов.

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

Сопровождение процесса

Подконтрольный запуск

Весь процесс тестирования нужно отслеживать, что всё идёт по плану. Запуск первых тестов на ночь, перед уходом с работы — наиболее частая ошибка. В таком случае очень часто можно получить такие варианты развития событий:

  1. Тест упал сразу после запуска по причине мисконфига.
  2. Тест упал в середине работы из-за нехватки какого-то ресурса.
  3. Тест частично упал или частично не запустился.
  4. Автоматизированные тесты наложились один на другой.

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

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

Узкие места

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

  1. Клиенты боролись за локальный ресурс. Например, ЦПУ гипервизора.
  2. Локальные перегрузки на сети из-за неудачной балансировки.
  3. Что угодно, что могло быть замечено в процессе теста или сразу после первого прогона и влияет на результат.

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

В статистике и результатах нужно искать любые аномалии — перегрузка, неравномерная нагрузка, отсутствие нагрузки. Любые странности должны насторожить оператора.

Документирование

Необходимо документировать всё. Все успешные результаты тестов должны сохраняться на будущее в исходном формате. Это даст возможность повторно построить какие-то графики в будущем, если возникнет такая необходимость.

Структуру хранения результатов так же стоит продумать заранее, она не должна сильно изменяться в будущем. Например, разделить по каталогам по номеру задачи, с подкаталогами по названию теста, далее по количеству клиентов, а ссылки на задачи держать в wiki. Четкая структура сильно облегчает обращение к историческим данным, например для построения сравнительных графиков нескольких кластеров.

Интерпретация результатов

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

Если же с увеличением количества клиентов добиться деградации качества обслуживания не удалось, то возможно стоит подумать над увеличением лимитов.

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

  1. Утилизация ЦПУ, как на хостах хранилища, так и у клиентов. Нужно смотреть не только общую нагрузку, но и распределение нагрузки по ядрам, отсутствия длительного ожидания в очереди на ЦПУ. Что происходит, когда система начинает деградировать? Не ошибка ли это в выборе железа или количества сервисов на хост? Или ЦПУ тратит время в ожидании какого-то ресурса?
  2. Утилизация и перегрузка сети. Раз мы работаем с сетевым хранилищем, то стоит посмотреть, не оказалась ли сеть бутылочным горлышком. Дропы, ошибки и утилизация — основные параметры.
  3. Утилизация и латенси дисков. Опять же, это ведь хранилка. В идеальном мире самым медленным элементом системы должен быть конечный элемент. Т.е. не должно быть узких мест, система должна быть настроена так, чтобы реализовать потенциал дисков. В реальности, во-первых, нужно опять-таки учитывать профиль нагрузки, а во-вторых, реализовать потенциал дисков иногда невозможно.

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

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

В итоге

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

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

Собираем статистику и подключаем мониторинг. Эти две вещи сэкономят время на тестировании и помогут с интерпретацией результатов.

Описываем окружение и чем точнее, тем лучше.

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

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

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

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

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

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

Ссылки


₽ с или .