Иногда бывает довольно сложно сэкономить на Spot Instance Amazon Web Services (AWS). Не стоит забывать, что по сути это — аукцион. Цены хоть и не меняются так же резко, как на биржах, тем не менее могут расти, пока не достигнут ondemand. Бывает, что такое продолжается не день и не два, а до нескольких месяцев, что приводит к повышению расходов вдвое на обычные ресурсы.
Как не попасть в ситуацию, когда, например, в ноябре всё прошло отлично, а в декабре из-за праздничного ажиотажа прайс удвоился, и вы получили не только дорогую систему, а ещё и с прерыванием? Давайте разберем причины, почему так происходит. Для этого рассмотрим стратегии распределения Spot Instance и поймем, как можно использовать модуль Terraform без всех этих проблем и при этом еще и сэкономить. В этом нам поможет инженер по облачным сервисам и архитектор AWS Владимир Самойлов, участник сообщества FivexL.
Spot Instance — это незадействованный EC2 (Elastic Compute Cloud), который выставляется на торги по минимальной цене. Его главный недостаток — в прерываниях, и вы всегда должны быть готовы к ним, как к постоянному явлению, которое точно произойдет. Прерывания для Spot Instance не есть что-то специфичное — это часть рабочего процесса, а не какой-то инцидент.
Есть три основных причины прерываний:
Текущая цена стала выше той, которую вы готовы заплатить.
Закончились spot Instance того типа, который вы используете.
Дополнительные ограничения, которые вы сами установили. Например, сначала вы выставили все зоны доступности, но потом оставили только одну.
Информация о прерываниях будет доставляться через EC2 Metadata Service и EventBridge. С их помощью можно сделать какие-то обработки, но стоит помнить, что SLA у AWS на один инстанс — это всего лишь 90%, поэтому нужно ожидать прерываний во всех инстансах, а не только в спотах.
Простые рекомендации для борьбы с прерываниями
Добавить устойчивости и эластичности
Чтобы сделать ваши Spot Instance более устойчивыми и эластичными, используйте Auto Scaling Group. Тогда в случае прерывания можно завершить какие-то действия или, как минимум, получить новый инстанс взамен предыдущего.
Повысить вероятность запуска
AWS и сам по умолчанию использует разные типы инстансов. Но если вручную создать «Auto Scaling Group», то вы получите полный список типов возможных инстансов. И если какого-то типа у вас нет, то можно использовать другие. В некоторых случаях — даже их прошлые поколения.
У AWS есть статистика по всем типам со своей вероятностью прерывания по каждому региону. Поэтому начинать подбор Instance Type лучше всего с сервиса Spot Instance Advisor. Он подскажет какие типы лучше взять для каждого конкретного региона. На одной странице их можно быстро отсортировать — например, какие в прошлом месяце были меньше подвержены прерываниям.
Стратегии распределения Spot Instance
Есть несколько стратегий распределения. Они влияют на то, из каких Spot Pool (групп неиспользованных EC2, объединенных общей зоной доступности и типом) будет запущен Spot Instance.
Стратегия по умолчанию
По умолчанию стратегия распределения — это Capacity optimized. С ней вы получите Spot Instance из наиболее доступных Spot Instance Pool. При этом, если сочетать ее с Auto Scaling Group, то будет выбран только один тип на каждую зону доступности — который прервется с меньшей вероятностью.
Эта стратегия очень хороша при нагрузках, которые дорого прерывать, но если вы хотите достичь большей экономии, то есть альтернатива.
Наименьшая цена
Эта стратегия позволит сделать выборку Spot Instance из нескольких Spot Instance Pool в каждой зоне доступности с наименьшей ценой за спот. Можно даже указать — из какого количества спотов. По умолчанию стоит два, а максимально можно установить 20 штук.
Это тоже хорошо сочетается с Auto Scaling Group и множеством типов, т.е мы можем получить разные типы инстансов в разных зонах доступности. Это удобно, но стоит помнить, что наименьшая цена предполагает наибольшее количество прерываний, потому что у нас уже не будет подсказок о том, какой Spot Pool имеет наименьшую вероятность прерывания.
Устойчивость с Capacity rebalance
С 5 ноября 2020 года появилась еще одна возможность повысить устойчивость спотов с помощью нового сигнала EC2 Rebalance Recommendation. Он может поступить раньше, чем стандартное двухминутное уведомление о прерывании Spot Instance. С его появлением EC2 Autoscaling выпустили новую функцию — Capacity rebalance:
Остановимся на ней подробнее, потому что она добавила спотам больше устойчивости. Вначале вы получаете сообщение о появлении сигнала Capacity rebalance. Затем Auto Scaling Group (либо сторонний скрипт, который у вас есть и получил этот сигнал), запускает новый инстанс, проходящий все свои процессы. После чего инстанс, у которого повысилась вероятность прерывания и получивший сигнал Capacity rebalance, начинает процесс завершения.
Для корректного завершения наконец-то появилась возможность правильно обработать завершение Spot Instance. Можно использовать Lifecycle hook Auto Scaling Group, обработать termination либо взять событие из EventBridge и запустить по нему какую-то лямбду с какой-то логикой. Например, в случае контейнеризации, то есть ECS или EKS, можно выгнать все Pods/ECS Tasks с этого инстанса и не прервать нагрузку вообще.
Возможно, для кого-то этих простых рекомендаций уже будет достаточно, но посмотрим еще, как можно сочетать экономию и высокую эффективность.
Сколько стоит Spot Instance?
Это, наверное, самый важный вопрос. Для ответа есть пара инструментов:
Привычный всем Cost Explorer, с базовой и доступной всем информацией;
Дополнительный Spot Instance data feed — детальный отчет в S3, который задействуется в настройках.
Сначала рассмотрим, как можно использовать Cost Explorer. Группируем споты по Instance Type, фильтруем по Usage Type Group EC2 Running Hours, дополнительно ставим важную опцию Purchase Option Spot. В результате получаем два графика: Costs и Usage:
Теоретически по ним можно определить среднюю цену за день, если разделить одно на другое. Если еще добавить фильтры по тегам, то можно в целом понять, что происходит. Но если в результатах будет много разных типов инстансов, то это довольно сложно. Плюс, по умолчанию нет детального распределения по часам. Конечно, его можно включить в Cost Explorer, но для данной задачи она не особо требуется, и к тому же стоит денег.
Поэтому лучше посмотрим на Spot Instance data feed. Информация на него приходит каждый час, но с задержками. Имейте в виду, что согласно тестам, задержки могут быть от 15 минут до нескольких часов:
Самое главное, что в Spot Instance data feed можно получить — это детальная информация с типом инстанса, максимальной ценой, текущей рыночной ценой и, наконец — той цифрой, которую мы все же заплатили(колонка Charge). Из особенностей настройки этого процесса можно отметить только немного кастомный ACL для S3, но всё довольно просто решается.
Настройки Spot Instance data feed
Текущая стоимость называется Spot Price (колонка Charge). Эта цена устанавливается для каждой зоны доступности и Instance Type в зависимости от спроса и предложения на Амазоне. Она постепенно корректируется на основании долгосрочных прогнозов. Однако стоит помнить, что динамика изменений этой цены плавная — как вверх, так и вниз. То есть, за час она не изменится и если сегодня это был 1$, то завтра 3$ не станет.
Поэтому можно использовать важную, но менее известную настройку Spot Max Price. Это максимальная цена за Spot Instance, которую вы готовы заплатить. Как только она становится выше того, что вы указали, то вы просто перестаете платить. Часто Spot Max Price не настраивают, потому что раньше ее не было в UI и приходилось ставить её через SLA (сейчас ее добавили в Spot request).
Устанавливать Spot Max Price очень важно. Если не указать никакого значения, то вы автоматически соглашаетесь заплатить любую цену, вплоть до ondemand, это всегда потолок. Для примера посмотрите на динамику изменения цен во время декабрьских праздников для трех разных типов инстансов:
В начале самый выгодный тип — t3a, но из-за того, что в среднем он дешевле на 10%, спрос на него начинает расти. Его быстро покупают, и в какой-то момент более выгодным становится t3. А когда выкупают и его, то дешевле оказывается c5, что не очень ожидаемо.
Учитывайте, что часто на спотах встречается ситуация, когда spot instance “A” типа дороже, чем обычные. Чаще всего это обусловлено их популярностью — они дешевле на ondemand и их чаще покупают.
Кажется, и что же тогда делать? Отказаться от Spot Instance? Не спешите, для этой проблемы есть решение, и решить большую часть этих проблем без постоянного изучения Spot price history вам поможет Terraform-модуль.
Terraform-модуль
Модуль решает проблему автоматизации расчета Spot Max Price. У него есть несколько вариантов поведения, которые могут быть полезны:
spot_price_current_min — хотя бы один Instance Type в хотя бы одной AZ;
spot_price_current_optimal — хотя бы один Instance Type во всех AZ;
spot_price_current_max — все Instance Type во всех AZ;
spot_price_current_max_mod — все Instance Type во всех AZ с повышенной надежностью.
Пройдемся по ним от простого к сложному на примере матрицы цен:
Сначала получим текущий spot_price без открытия UI и Spot price history, это самый простой пример:
Видим, что достаточно передать всего лишь одну зону доступности, один тип инстанса и получить результат. Ответ здесь будет 0,20, потому что мы передали только r5 и только зону доступности 1a.
Минимальная цена
Немного более сложный пример, если ваша задача — запустить самый дешевый инстанс, который только возможно. В этой ситуации воспользуйтесь поведением spot_price_current_min:
В этом случае будут запускаться инстансы хотя бы одного Instance Type в одной зоне доступности. Но, несмотря на то, что передается несколько зон доступности, все инстансы окажутся в одной зоне, потому что выбрана только одна. Важно помнить, что самый дешевый инстанс всегда где-то только один.
Смотря в нашу таблицу, мы увидим, что в зоне доступности 1b есть только один инстанс типа r5a с минимальной ценой 0,10. В процессе изменения цен вы каждый раз будете получать самую минимальную цену. Например, если в одной зоне доступности начала расти цена, то при следующем Terraform apply вы получите следующую минимальную цену, допустим, из другой зоны доступности. Конечно, такое поведение вызовет самые частые прерывания, и если цена хотя бы немного вырастет, то вы сразу лишитесь этого инстанса.
Поэтому такое поведение не очень эффективно, и лучше поискать оптимальный баланс между ценой и доступностью.
Оптимальная цена
Это поведение дает возможность запустить хотя бы один Instance Type во всех зонах доступности, что избавит вас от проблемы с определением какой Instance Type выгоднее: t3, t3a, c5 или какой-то из r. При изменении цен будет переключение на самые выгодные типы инстансов для каждой зоны доступности, а в случае повышения цен вы будете терять зоны доступности по одной, как и в случае их отключения. Вернувшись к таблице, видим намного больше вариантов:
В зоне доступности 1c по цене 0,20 будут только инстансы типа r5. Но если они, допустим, вырастут в цене до 0,30, то у вас останутся еще две зоны доступности и два других типа инстансов. Важно отметить, что такой переход будет с прерыванием работы тех инстансов, чья цена стала выше. Но в мире спотов всегда нужно быть готовым к прерываниям, как к постоянному явлению.
Все предыдущие выборы подразумевали наибольшую экономию, но если вам нужна более высокая стабильность, то подойдет поведение spot_price_current_max.
Максимальная текущая цена
При таком поведении могут быть запущены все типы инстансов во всех зонах доступности. Это решит проблему отсутствия Spot Instance за счет определения цены для разных типов. Также такое поведение допускает большую задержку между Terraform apply, и их можно будет запускать реже. Это особенно удобно, если модуль запускается где-то вручную, а не в CI/CD.
Судя по таблице, в этом случае может быть запущен любой Instance Type в любой AZ, потому что ни один из них не превышает максимальную цену. Это значит, что если вы запустите r5 в 1a, который стоит 0,20, то будете платить эту цену вплоть до ее повышения до 0,30. Такое поведение позволяет не зависеть от типов инстансов и зон доступности. Если добавить много типов инстансов, то можно покрыть вообще все кейсы и быть всегда со спотами.
Модифицированная цена
На случай, если нужно еще больше стабильности, и вы готовы иногда доплачивать за это на 5-10% больше, есть поведение spot_price_current_max_mod:
Это поведение снижает вероятность прерывания из-за незначительных колебаний цены и поможет если Terraform запускается очень-очень редко или в ручном режиме. Вы сможете заранее указать, что готовы платить, например, плюс 10% к текущей цене, то есть 0,33 вместо 0,30. Это небольшая переплата за снижение прерываний.
Но стоить помнить, что переплата сильно зависит от количества инстансов, которые вы используете. Разница в +2 цента может вылиться в 14$ за месяц на каждый EC2 Instance, а если их 100 — превратиться в 1400$. Поэтому просчитывайте, стоит ли того снижение вероятности прерываний. Если вы все-таки считаете, что стоит, то через custom price modifier это поведение можно применить ко всем другим сценариям.
Области применения EC2 Spot Price-модуля
Самая основная проблема, которую решает Terraform-модуль — это не дает отпустить цену до самого потолка, чтобы не получить удвоения прайса. Поэтому его можно применять везде, где используется Auto Scaling Group.
Если у вас есть ECS Capacity провайдер, EKS-worker ноды, GitLab runners, любая нагрузка, которую можно прервать, билд-машины, побочные вещи мониторинга, DevTest окружение — их можно запускать полностью на спотах. Если в ECS использовать специальный флаг ECS_ENABLE_SPOT_INSTANCE_DRAINING или для EKS применять EKS Node Termination Handler, то можно запускать даже продакшн. Есть примеры, когда он целиком работает на спотах.
Но более типичные примеры — когда запускают один-два ondemand инстанса на случай, если у вас всё заберут. А всё, что скейлится, отправляют на споты, потому что неизвестно какая будет нагрузка и ничего нельзя заранее купить.
Полезные ссылки по теме:
https://aws.amazon.com/ru/ec2/spot/instance-advisor/
https://ec2spotworkshops.com/ https://github.com/awslabs/ec2-spot-labs/
https://github.com/aws/aws-node-termination-handler
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-instance-spot.html
Видео моего выступления на devopsConf 2021:
13 и 14 июня конференция TechLead Conf 2022 пройдет совместно с конференцией DevOpsConf 2022. Место проведения — кампус Сколково, самая инновационная и технологичная площадка в Москве.
Обсудим инженерные процессы в IT от XP до DevOps & Beyond, must have инструменты и практики изменений в командах для быстрых и качественных релизов. Программа практически сформирована. Билеты можно купить здесь. До повышения цены осталось 3 дня!
Также Программный комитет DevOps 2022 ждет ваших заявок о выступлении на конференции — появились новые темы. От импортозамещения, переезда обратно из облаков — до новой инфраструктурной парадигм, рисков по железу и даже поддержки своих команд. Доклады по темам принимаются до 22 апреля.