Привет! Мы обучаем людей работе с большими данными. Невозможно себе представить образовательную программу по большим данным без своего кластера, на котором все участники совместно работают. По этой причине на нашей программе он всегда есть :) Мы занимаемся его настройкой, тюнингом и администрированием, а ребята непосредственно запускают там MapReduce-джобы и пользуются Spark'ом. В этом посте мы расскажем, как мы решали проблему неравномерной загрузки кластера, написав свой автоскейлер, используя облако Mail.ru Cloud Solutions. Кластер у нас используется не совсем в типичном режиме. Утилизация сильно неравномерная. Например, есть практические занятия, когда все 30 человек и преподаватель заходят на кластер и начинают им пользоваться. Или опять же есть дни перед дедлайном, когда загрузка сильно возрастает. Во все остальное время кластер работает в режиме недозагрузки. Решение №1 – это держать кластер, который будет выдерживать пиковые загрузки, но будет простаивать во все остальное время. Решение №2 – это держать небольшой кластер, в который вручную добавлять ноды перед занятиями и во время пиковых нагрузок. Решение №3 – это держать небольшой кластер и написать автоскейлер, который будет следить за текущей загрузкой кластера и сам, используя различные API, добавлять и удалять ноды из кластера. В этом посте мы будем говорить о решении №3. Такой автоскейлер сильно зависит от внешних факторов, а не от внутренних, и провайдеры его часто не предоставляют. Мы пользуемся облачной инфраструктурой Mail.ru Cloud Solutions и написали автоскейлер, используя API MCS. А так как мы обучаем работе с данными, решили показать, как вы можете написать подобный автоскейлер для своих целей и использовать со своим облаком Во-первых, у вас должен быть Hadoop-кластер. Мы, например, пользуемся дистрибутивом HDP. Чтобы у вас ноды могли быстро добавляться и удаляться, у вас должно быть определенное распределение ролей по нодам. Важный момент. Автоскейлинг будет происходить за счет нод третьего типа. Если вы начнете забирать и добавлять ноды второго типа, то скорость реагирования будет сильно низкой – декомишен и рекомишен будет занимать часы на вашем кластере. Это, конечно, не то, что ожидаешь от автоскейлинга. То есть ноды первого и второго типа мы не трогаем. Они будут представлять собой минимально жизнеспособный кластер, который будет существовать на протяжении всего действия программы. Итак, наш автоскейлер написан на Python 3, использует Ambari API для управления сервисами кластера, использует API от Mail.ru Cloud Solutions (MCS) для запуска и остановки машин. Давайте теперь посмотрим на куски кода, находящиеся внутри первых двух файлов. Так выглядит кусочек кода, содержащий класс Ambari: Выше для примера можно посмотреть на реализацию функции stop_all_services, которая останавливает все сервисы на нужной ноде кластера. На вход классу Ambari вы передаете:  Сама функция представляет из себя не более чем парочку обращений через REST API к Ambari. С точки зрения логики мы вначале получаем список запущенных сервисов на ноде, а затем просим на данном кластере, на данной ноде перевести сервисы из списка в состояние INSTALLED. Функции по запуску все сервисов, по переводу нод в состояние Maintenance и др. выглядят похожим образом – это просто несколько запросов через API. Так выглядит кусочек кода, содержащий класс Mcs: На вход классу Mcs мы передаем id проекта внутри облака и id пользователя, а также его пароль. В функции vm_turn_on мы хотим включить одну из машин. Логика здесь чуть сложнее. В начале кода идет вызов трех других функций: 1) нам нужно получить токен, 2) нам нужно конвертировать hostname в название машины в MCS, 3) получить id этой машины. Далее мы делаем просто post-запрос и запускаем эту машину. Так выглядит сама функция по получению токена: В этом классе содержатся функции, относящиеся к самой логике работы. Так выглядит кусок кода этого класса: На вход мы принимаем классы Ambari и Mcs, список нод, которые разрешены для скейлинга, а также параметры конфигурации нод: память и cpu, выделенные на ноду в YARN. Также есть 2 внутренних параметра q_ram, q_cpu, являющихся очередями. При помощи них мы храним значения текущей нагрузки кластера. Если мы видим, что в течение последних 5 минут стабильно была повышенная нагрузка, то мы принимаем решение о том, что нужно добавить +1 ноду в кластер. То же самое справедливо и для состояния недозагрузки кластера.  В коде выше приведен пример функции, которая удаляет машину из кластера и останавливает ее в облаке. Вначале происходит декомишен YARN Nodemanager, дальше включается режим Maintenance, дальше мы останавливаем все сервисы на машине и выключаем виртуальную машину в облаке. Пример кода оттуда: В нем мы проверяем, сложились ли условия для увеличения мощностей кластера и есть ли вообще в резерве машины, получаем хостнейм одной из них, добавляем ее в кластер и публикуем об этом сообщение в Slack нашей команды. После чего запускается cooldown_period, когда мы ничего не добавляем и не убираем из кластера, а просто мониторим загрузку. Если она стабилизировалась и находится внутри коридора оптимальных значений загрузки, то мы просто продолжаем мониторинг. Если же одной ноды не хватило, то добавляем еще одну. Для случаев когда у нас впереди занятие, мы уже знаем наверняка, что одной ноды не хватит, поэтому мы сразу стартуем все свободные ноды и держим их активными до конца занятия. Это происходит при помощи списка таймстемпов занятий. Автоскейлер – это хорошее и удобное решение для тех случаев, когда у вас наблюдается неравномерная загрузка кластера. Вы одновременно добиваетесь нужной конфигурации кластера под пиковые нагрузки и при этом не держите этот кластер во время недозагрузки, экономя средства. Ну и плюс это все происходит автоматизированно без вашего участия. Сам автоскейлер – это не более, чем набор запросов к API кластер-менеджера и API облачного провайдера, прописанных по определенной логике. О чем точно нужно помнить – это о разделении нод на 3 типа, как мы писали ранее. И будет вам счастье. Education program designer