Как снизить затраты на облако
Август 25, 2022
Рынок облачных сервисов в России растет примерно на 20—25% в год. При этом расходы на облако тоже растут, и не всегда это связано с расширением деятельности предприятия или подключением новых услуг. Очень часто компании допускают ошибки при использовании облачных ресурсов, что приводит к неожиданным и существенным расходам.
В этой статье мы расскажем, какие ловушки таит в себе облако и как их избежать.
- Почему счета за облако такие огромные?
- Облачный мониторинг или жизнь после деплоя
- Заключение
- Полезные ссылки
- Еще по теме
Почему счета за облако такие огромные?
Часто осознание непомерных трат на облачные сервисы приходит внезапно. Ничто не предвещало беды: приложение продемонстрировало оптимальную пиковую производительность на чистом сервере, проблем с созданием контейнера и его масштабированием не возникло, требования SLA (соглашения об уровне сервиса) выполнены — что могло пойти не так? Всё, что угодно.
Даже не углубляясь в метрики, можно идентифицировать несколько типичных ошибок:
- Разработчики не участвуют в процессе оптимизации затрат. Они пишут код, не учитывая особенности среды исполнения. При этом администраторы Yandex Cloud или облачные алгоритмы могут не брать в расчет характеристики приложения или вообще не знают о них.
- SLA между поставщиком облачных услуг и компанией помогает обезопасить проект в облаке. Но если SLA составлено без учета наихудших сценариев, или в нем прописаны не все условия, существует риск непредвиденных издержек в экстренных ситуациях2.
- Производительность приложения на чистом сервере не равна производительности в кластере при разных нагрузках. Именно поэтому поды неожиданно падают, а HotSpot потребляет гораздо больше памяти на одном и том же инстансе.
- Незагруженные сервисы будут потреблять столько же ресурсов, сколько загруженные, если ко всем сервисам применять одинаковую стратегию масштабирования.
- Разработчики упаковывают приложения в контейнеры, используя настройки по умолчанию. В результате вы получаете контейнер, не отвечающий требованиям вашего бизнеса, занимающий слишком много места или недостаточно производительный.
Давайте подробнее остановимся на последних двух пунктах.
Дефолтные контейнеры — это черные ящики
Paketo Buildpacks, наиболее популярные билдпаки для контейнеризации, Cloud Native Buildpacks и другие подобные технологии позволяют создавать контейнерные образы прямо в Maven или Gradle. Пара кликов — и вы собрали маленький производительный контейнер. Но разработчики редко конфигурируют контейнеры самостоятельно, предпочитая дефолтные настройки, ведь если автоматически созданный образ нормально работает, зачем утруждаться?
Проблема с решениями «из коробки» в том, что, по сути, это черные ящики: разработчики не всегда знают с точностью, как эти решения работают. В результате контейнеры Paketo с настройками по умолчанию иногда используют память и CPU недостаточно эффективно. Более того, билдпаки пока не собирают контейнеры с российским ПО. Чтобы получить производительные, надежные, безопасные и маленькие контейнеры, нужно конфигурировать их вручную:
- Начните с настроек JVM и оптимизируйте такие параметры, как
-XX:+AlwaysActAsServerClassMachine
или
-XX:+PerfDisableSharedMem
Также следует выбрать подходящий сборщик мусора
- Протестируйте контейнер. Используйте нагрузочное тестирование, A/B, тестирование долговечности, спланируйте пропускную способность. Результаты тестирования под нагрузкой должны соответствовать варианту «без контейнера»
- Помните, что у каждого контейнера в поде должен быть установлен лимит используемой памяти и требуемая память
- При расчете требуемых ресурсов учитывайте размеры узла для правильного планирования его работы
- Технический оверхед может быть невелик, но учитывайте также оверхед Kubernetes. Например, Fargate использует дополнительные 256 МБ оперативной памяти
- Для уменьшения размера контейнеров без ущерба безопасности и производительности можно использовать Axiom JDK Lite, оптимизированную для облачных систем, и легковесную Alpine Linux
После развертывания приложения в облаке необходимо выполнять непрерывный мониторинг «здоровья» узлов и подов, ежедневно выполнять нагрузочное тестирование и контролировать метрики: время отклика, пропускную способность, статистику GC и т.д. Более подробное описание мониторинга метрик приведено в разделе «Жизнь после деплоя».
Как видите, контейнеры требуют внимания и заботы. Автоматические настройки удобны, но если хотите сделать что-то хорошо, сделайте это сами.
Недостаточное и чрезмерное использование ресурсов
С технической точки зрения все сервисы одинаковые, но неправильное распределение памяти приводит к недостаточному или чрезмерному использованию ресурсов. В случае чрезмерного потребления сервис нагружен до предела и поглощает много ресурсов, в результате чего
- Приложение не работает надлежащим образом, а занимается постоянной сборкой мусора
- Нужно поднять еще один инстанс, что автоматически удваивает расходы
Что касается недостаточно эффективного потребления, приложение не использует всю доступную память, что ведет к похожим проблемам: непрерывной сборке мусора и запуску дополнительных инстансов.
У этих проблем одна причина: установленный лимит памяти не соответствует функционалу приложения.
SLO или SLA? И то, и другое!
В первом разделе мы отметили важность правильно оформленного SLA между вами и поставщиком облачных услуг. Здесь речь пойдет о ваших обязательствах перед клиентами и/или пользователями. SLA заключается между компанией и коммерческими пользователями, поэтому если ваше ПО распространяется бесплатно, SLA вам не нужно. В противном случае, не забудьте привлечь к составлению договора не только адвокатов, но и разработчиков, так как только они знают, сколько требуется времени и ресурсов для выполнения того или иного условия SLA.
То же касается и SLO. Если в SLA прописываются обязательства компании перед клиентом, то в SLO (цели уровня обслуживания) указаны цели, которые команда должна достичь для выполнения требований SLA. Цели SLO должны быть четкими, реалистичными и привязанными к SLA. Выберите самые важные метрики, проанализируйте их и обговорите цели вместе с разработчиками. Также не забудьте включить в SLO и SLA наихудшие сценарии.
Облачный мониторинг или жизнь после деплоя
Мы рассмотрели основные ошибки, ведущие к большим затратам на облачные сервисы. Допустим, вы уже развернули в облаке свое приложение, но не уверены, какие показатели нужно анализировать. Где кроется проблема: в JVM, приложении, контейнерах, SLA? Ниже приведены метрики, обеспечивающие вас всеми необходимыми данными для последующей оптимизации.
Метрики Kubernetes
Начните с получения метрик Kubernetes, чтобы иметь представление о том, что происходит в ваших кластерах. Для этого можно использовать опенсорсные инструменты, например, Metrics Server, и различные команды kubectl
.
Установите Metrics Server. Возможно, он уже работает в вашем кластере. Проверить это можно с помощью команды
kubectl get pods --all-namespaces | grep metrics-server
Если Metrics Server запущен, вы получите список всех работающих подов. В противном случае для установки последней версии ПО выполните
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Metrics Server позволяет получать данные о доступных ресурсах: CPU, памяти, хранилище, а также о том, как они используются. kubectl top
предоставляет метрики конкретного узла, пода или всех узлов и подов кластера.
Например, выполнив
kubectl top node
вы получите данные об использовании CPU и памяти со всех узлов.
Чтобы получить данные со всех подов:
kubectl top pod
Команда
kubectl top pod --namespace=kube-system –-container
Вернет данные об использовании ресурсов контейнерами в поде.
Команда
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes/<NODE_NAME> | jq
или
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/<NAMESPACE>/pods/<POD_NAME> | jq
вернет Metrics API в формате JSON с пода или узла.
Еще один полезный инструмент — kube-state-metrics
, возвращающий состояние узлов и подов: статус, емкость, количество реплик на деплой и т.д.
Наконец, можно использовать
kubectl logs
для получения подробной информации о подах и узлах.
Данные GC
Java-приложения управляют используемой памятью с помощью сборщика мусора (GC). Настройка GC может значительно повлиять на производительность. Но для начала нужно понимать, что происходит со сборкой мусора в приложении. С этим помогут логи GC.
Сперва активируйте логи GC:
-Xlog:gc*:<gc.log file path>:time
После этого логи можно собирать с помощью централизованного управления логами или APM-систем. Также можно анализировать отдельные логи. Логи GC генерируются в текстовом формате, их можно обрабатывать с помощью скриптов или десктопных/онлайн инструментов анализа логов GC.
JFR — еще один полезный инструмент мониторинга. Его можно использовать для выявления проблем с памятью или причин Stop-the-World пауз. JFR регистрирует события GC, которые затем обрабатываются с помощью JDK Mission Control или APM. Также можно использовать мониторинг JMX.
Пропускная способность GC — это соотношение времени, затраченного на выполнение бизнес-логики, и общего времени, включающего работу GC и другую сервисную деятельность JVM. Ресурсы CPU используются правильно, если CPU-нагрузка и пропускная способность GC близки к 100%.
Производительность под нагрузкой
Не забывайте, что приложения в облаке и под высокой нагрузкой могут вести себя по-другому. Никогда не полагайтесь на базовые показатели производительности и знайте пределы и требования CPU и оперативной памяти. Вот несколько основных советов:
- Выполняйте нагрузочное тестирование, чтобы понимать поведение приложения как в нормальных условиях, так и и под пиковой нагрузкой
- Выполняйте тестирование долговечности для оценки стабильности и устойчивого качества приложения
- Определите пиковую нагрузку и время отклика. Любая система может неожиданно дать сбой, но необходимо принять профилактические меры для снижения этого риска. Учитывайте, что пиковые нагрузки связаны с высоким потреблением ресурсов
- Определите требования CPU и оперативной памяти для каждого сервиса
- Используйте модели сервисов для упрощения тестирования
Анализ статистики VM
Настройка JVM не ограничивается оптимизацией GC. На самом деле, настройка производительности JVM — сложная задача, требующая отдельной статьи. Но перед оптимизацией настроек нужно научиться получать метрики JVM и выполнять мониторинг JVM.
Получать метрики производительности на клиентской машине можно с помощью инструментов нагрузочного тестирования, например, JMeter или wrk. Также можно анализировать внутренние метрики, полученные бэкендом и собранные APM. Метрики получают с разных уровней:
- Машины
- JVM
- Веб-сервера, системы BigData, очереди сообщений и т.д.
- Приложения
Часто клиентам важно время отклика. Оно измеряется в определенных процентилях (50%, 95%, 99%, 99,99%, 99,9999%). Поэтому его можно изучить под разными углами, например, с точки зрения общего времени выполнения приложения или времени выполнения по достижению пиковой производительности.
Заключение
В этой статье мы рассказали, как получать метрики, помогающие выявить проблемы с потреблением ресурсов в кластере. Самое главное — никакие дефолтные настройки, алгоритмы и инструменты автоматизации не оптимизируют потребление ресурсов в соответствии с вашими требованиями. Для этого нужно самостоятельно конфигурировать контейнеры и JVM.
Полезные ссылки
Еще по теме
Работаете с контейнерами? Узнайте, как избежать побочных эффектов контейнеризации
Хотите уменьшить размер своей ОС? Узнайте, как Linux удается сохранить адекватный функционал при минимальном размере на примере Alpine Linux