Примечание редактора: судя по всему, в 2026 году от Рождества Христова это необходимо пояснять: каждое слово этого поста (как и любого другого в данном блоге) порождено моим крошечным человеческим мозгом из мяса. Ни одна языковая модель никакого сорта не участвовала в написании, генерации или производстве какого-либо контента.
В начале этого года мне довелось пообщаться с https://www.usenix.org/conference/srecon24americas/speaker-or-organizer/courtney-nash-void-01 на SREcon, и она напомнила мне кое-что важное: «говорить о себе как об эксперте — это нормально». Так в чём же я эксперт? Последние десять с лишним лет я занимаюсь автомасштабированием (autoscaling) распределённых систем. Я создал Clusterman в Yelp — сначала для Apache Mesos, затем перевёл его на Kubernetes; вносил вклад в Kubernetes Cluster Autoscaler и Karpenter; помогал множеству компаний наладить автомасштабирование как следует. Так что, думаю, можно с уверенностью назвать себя экспертом в этой области.
Автомасштабирование — тема занятная: из тех, что поначалу кажутся несложными, но стоит копнуть глубже — и обнаруживается масса нюансов. Масштабироваться реактивно или пытаться предсказать, когда понадобятся новые ресурсы? Как долго держать неиспользуемые ресурсы, прежде чем уменьшить масштаб? Как выставить ограждения, чтобы система не вышла из-под контроля, и что делать, когда приложения упираются в эти ограждения в штатном режиме? Как меняются ответы на все эти вопросы во время инцидента или сбоя по сравнению с нормальной работой?2
Поэтому в ближайшие несколько недель я решил подробно разобрать тему автомасштабирования: зачем мы это делаем и как делать хорошо? В ACRL мы выделили пять «ключевых метрик», за которыми нужно следить в своих движках автомасштабирования, — и, спойлер, это, возможно, не те метрики, о которых вы думаете. В этом посте дадим общий обзор, а в следующих углубимся в детали. Интересно? Читайте дальше!
Зачем мы масштабируемся автоматически?
Прежде чем говорить о чём-либо ещё, важно понять, зачем мы вообще занимаемся автомасштабированием. Причин две. Первая — та, о которой все говорят, — деньги. Когда вы были крошечным стартапом, у вас были щедрые AWS-кредиты и не так много инфраструктуры, поэтому вы просто избыточно выделяли ресурсы подо всё подряд — а почему нет? Всё равно бесплатно. Но в какой-то момент кредиты заканчиваются, инфраструктуры становится много, и к вам приходит вице-президент по финансам с распечаткой счёта. Что делать? Внедрить автомасштабирование! Делов-то! Пара недель работы техлида, колоссальная экономия, проблема решена!
На деле всё оказывается не так просто: через две недели техлид «прикрутил автомасштабирование», и у вас случается первый связанный с ним сбой. Упс. Дальше — месяцы или годы усилий по балансировке между экономией и надёжностью. Самое время написать OKR!
Этот пример иллюстрирует мысль, которую я повторял сотни раз: стоимость и надёжность диаметрально противоположны. Можно сделать систему сверхнадёжной, закупив самые мощные и дорогие вычислительные ресурсы3, — но тогда вице-президент по финансам снова постучит в дверь. С другой стороны, можно сделать систему предельно дешёвой, отключив все вычисления, — но тогда к вам придёт генеральный директор, потому что компании больше не существует. Это, конечно, крайности; на практике вы постоянно балансируете между ними.
Однако есть ещё одна причина для автомасштабирования, о которой большинство не говорит, — и я бы поспорил, что она ещё важнее. Даже если вы всегда работаете на пиковой мощности, рано или поздно ваш стартап упрётся в ограничения. Вы же компания гиперроста! Удваиваете аудиторию каждые две недели! Поздравляю, вы победили в капитализме!
В прошлом веке с этим справлялись через скрупулёзный аналитический процесс под названием «планирование ёмкости» (capacity planning). В отличие от сегодняшнего дня, когда новую машину у AWS можно попросить и получить почти мгновенно4, между «заказом нового железа» и его появлением в дата-центре проходило от трёх месяцев до года — а до момента, когда оно реально готово к работе, ещё несколько недель или месяцев сверху. Нужно было предсказывать потребности в вычислительных ресурсах за три месяца — год вперёд. Ошиблись — удачи.
Автомасштабирование упрощает эту задачу: оно не отменяет планирование ёмкости, но даёт больше пространства для манёвра, когда прогнозы не сбываются. Это не про деньги — это про долгосрочную жизнеспособность бизнеса. И, по крайней мере для меня, это крайне весомый аргумент в пользу того, чтобы думать об автомасштабировании, даже когда компания ещё мала.
Что именно можно масштабировать автоматически?
Разговоры об автомасштабировании часто запутывают, потому что каждый подразумевает чуть разное. Как отрасль мы пришли к трём типам масштабирования — дам им краткий обзор, а потом выскажу, вероятно, спорное утверждение: «все они — одно и то же».
Автомасштабирование узлов (node autoscaling): именно это мы изучали в моём сравнении Kubernetes Cluster Autoscaler и Karpenter. Сколько вычислительных ресурсов нам нужно в каждый момент времени, и можем ли мы получить их у облачного провайдера? В большинстве организаций это зона ответственности платформенных или инфраструктурных команд.
Горизонтальное автомасштабирование приложений (horizontal autoscaling): если масштабирование узлов управляет железом, масштабирование уровня приложений управляет программами. Сколько экземпляров вашего веб-сервера должно работать одновременно? Сколько шардов нужно базе данных? Как правило, этим занимается команда, владеющая приложением или сервисом. Одни приложения масштабируются отлично (например, stateless-веб-сервер), другие — не очень (добавить реплики чтения для базы данных обычно несложно, но масштабировать реплики записи куда труднее).
Вертикальное автомасштабирование (vertical autoscaling): его ещё называют «правильным подбором ресурсов» (right-sizing) — это менее распространённый вид5. Если горизонтальное масштабирование отвечает на вопрос «сколько копий приложения мне нужно?», вертикальное отвечает на вопрос «сколько вычислительных ресурсов нужно одной копии приложения?». Вертикальным масштабированием, как правило, тоже занимается владелец приложения, но, как уже было сказано, к нему обращаются реже. Важно отметить: при неаккуратной реализации между вертикальным и горизонтальным масштабированием возникает неприятная петля обратной связи, поэтому использовать оба одновременно можно только при грамотном подходе.
Теперь вернёмся к моему изначальному тезису, который я назвал спорным: все три типа автомасштабирования — одно и то же. Или, точнее, все они отвечают на один вопрос: «Как обеспечить приложению ресурсы, необходимые для выполнения текущих задач прямо сейчас?» Разбиение на три категории существует лишь затем, чтобы упростить рассуждения6.
В идеальном мире у нас был бы единый автомасштабировщик, работающий примерно так7:
-
Ой, мы не справляемся с нагрузкой приложения прямо сейчас!
-
Что поможет исправить ситуацию? Варианты:
-
добавить железо;
-
добавить программные копии;
-
увеличить ресурсы для существующих копий;
-
какая-то комбинация вышеперечисленного;
-
какая-то комбинация вышеперечисленного плюс вытеснение чего-то ненужного прямо сейчас.
-
-
Выполнить выбранное в шаге 2.
Если хочется совсем изощриться — поверх всего этого можно набросить алгоритм машинного обучения и добавить предиктивные возможности. Но я бы сказал, что в 98% случаев, если новые ресурсы удаётся выделить достаточно быстро, предиктивное масштабирование не нужно.
Итак, мы разобрались, зачем мы масштабируемся и как это можно делать. Завершим пост ответом на вопрос: «Как понять, что мы делаем это хорошо?»
Пять ключевых метрик автомасштабирования
Большинство организаций смотрит на одну метрику: выделенная ёмкость против запрошенной. По сути, это взгляд исключительно со стороны затрат. Чем выше утилизация, тем меньше ресурсов нужно и тем меньше денег уходит AWS. Но, как мы уже выяснили, такой взгляд крайне ограничен. Автомасштабирование — инструмент, с помощью которого мы находим своё место на спектре «стоимость — надёжность — планирование ёмкости». Если вы не отслеживаете метрики во всех трёх измерениях, вы летите вслепую. Поговорим о Пяти Ключевых Метриках Автомасштабирования по версии ACRL :tm:
-
Процент использования выделенной ёмкости (committed capacity percentage) — я уже описал эту метрику, но для полноты картины: она показывает, «сколько ресурсов вы тратите впустую». Чем выше committed capacity, тем меньше денег улетает в никуда. Просто и понятно.
-
Частота ошибок (error rates) — если committed capacity измеряет стоимость, частота ошибок измеряет надёжность. Когда приходит всплеск трафика и нужно масштабироваться вверх, вы сыплете ошибками, пока ёмкость не поспевает? Когда начинаете масштабироваться вниз, прерываете ли вы кучу незавершённых запросов и вынуждаете их повторять? Или у вас налажено плавное масштабирование — и вверх, и вниз?8
-
Среднее время до первого байта (Mean Time to First Byte, MTFB) — концепцию я позаимствовал у фронтенд-сообщества, где есть понятие «среднее время до контента» (mean time to content): сколько времени проходит с момента, когда пользователь вводит URL, до момента, когда он может что-то делать на странице? MTFB — аналогичная идея: сколько времени проходит с момента, когда автомасштабировщик решил увеличить масштаб, до момента, когда приложение или сервис реально делает полезную работу?9 Если committed capacity и error rates отслеживают стоимость и надёжность, то MTFB отслеживает «отзывчивость масштабирования».
-
Нарушение работы приложений (application disruption) — эта метрика — моя личная боль, потому что Kubernetes фактически не даёт инструментов для управления ею. В идеале ваш движок автомасштабирования не должен постоянно прерывать работающие поды и вынуждать повторять одну и ту же работу: это просто расточительно. Развёрнутый rant по этой теме — впереди.
-
Нестабильность приложений (application churn) — о последней метрике говорят редко, но каждый, кто писал автомасштабировщик (или, в принципе, любую инженерную систему), сталкивался с этой проблемой: автомасштабировщик считает, что нужно два с половиной экземпляра, но два с половиной иметь нельзя, поэтому получается два. Потом три. Потом два. Потом три. Потом два. И так далее… Загляните-ка в статью про https://en.wikipedia.org/wiki/PID_controller10.
Вот и всё! Отслеживайте эти метрики, оптимизируйте автомасштабировщик сразу по всем пяти — и готово!
Ахахахаха. Хаха! ХАХА! Я даже с серьёзным лицом это не могу сказать11. В общем, в следующие несколько недель мы подробно рассмотрим каждую из этих метрик и приведём примеры из практики: почему они важны и что бывает, когда на них не обращают внимания.
Как всегда, спасибо за чтение.
~drmorr
1 Которая, к слову, замечательный человек!
2 Я сбился со счёта, сколько раз видел или участвовал в инцидентах, когда система теряет весь трафик, автомасштабировщик всё сворачивает (трафика нет — незачем держать ресурсы!), а когда трафик возвращается, случается второй сбой «эффекта стада» (thundering herd), потому что ресурсов для обработки нагрузки уже нет.
3 Это стратегия Anthropic, но почему-то не похоже, что она им особо помогает.
4 Если только речь не о GPU-узлах, вздох.
5 Впрочем, с появлением изменения размера пода на месте (in-place pod resizing) в Kubernetes 1.35 я ожидаю, что вертикальное масштабирование будут пробовать значительно чаще.
6 Если хочется совсем запутать картину: я также считаю, что планирование (scheduling) — то же самое! Иначе почему каждый существующий автомасштабировщик запускает симуляцию планирования как часть своей петли обратной связи?
7 Внимательные читатели заметят, что это просто «избавление от лишних слоёв» — концепция, о которой я давно не писал в блоге, но думаю о ней практически постоянно.
8 «Но, Дэвид, — слышу я, — я всего лишь скромный платформенный инженер, а всё это контролирует команда сервисной сети! Я не могу управлять тем, как делаются повторные попытки!» На что отвечаю: «Не заставляйте меня тыкать пальцем в табличку со словом "слои"».
9 В большинстве других статей по теме смотрят на «среднее время до планирования» — то есть сколько времени проходит между действием автомасштабировщика и запуском приложения. Но запущенное приложение — не обязательно полезное, а нас интересует полезное. Возражение здесь то же, что раньше: у нас нет контроля над стеком приложения! Снова: табличка. Слои.
10 В последнее время я часто разговариваю с людьми о том, как сообщество разработчиков ПО упорно отказывается перенимать уроки из других инженерных дисциплин, существующих задолго до него, и вместо этого трактует каждую проблему как «абсолютно новую, которую никто в мире никогда не встречал и не мог бы понять». Метрика «нестабильности приложений» — увы, из той же оперы.