8 lines
18 KiB
JSON
8 lines
18 KiB
JSON
{
|
||
"index": 115,
|
||
"slug": "editorial-2024-10-field-capacity-cost",
|
||
"title": "Ёмкость и стоимость: как выбрать следующий предел, а не самый большой инстанс",
|
||
"excerpt": "Большой инстанс может улучшить одну latency-метрику и одновременно увеличить расход и операционный риск. Разбираем причинную цепочку, проверку и безопасный критерий следующего шага.",
|
||
"contentHtml": "<p>На разборе ёмкости команда видит знакомую картину: p95 снизился после перехода на 4 CPU, а счёт и запас зарезервированных ресурсов выросли. Вторая карточка с 1,6 CPU показывала очередь и почти касалась SLO, поэтому большой инстанс кажется очевидным ответом. Цена ошибки — закрепить дорогой reservation без доказанного эффекта, принять одну удачную latency-точку за решение и потерять понятный путь возврата.</p>\n<p><strong>Тезис:</strong> ёмкость выбирают не по лучшему p95, а по следующему проверяемому пределу. Сравните performance, модель стоимости и операционный риск в одном scope. Запишите условие остановки до выбора размера. Если хотя бы одна ось не объяснена, остановитесь и запросите недостающие данные.</p>\n<h2>Что именно нужно сравнить</h2>\n<p>Сначала зафиксируйте workload, период, единицы и формулу стоимости. Затем разделите четыре слоя. <code>request</code> описывает ресурс, который workload просит у планировщика. <code>limit</code> задаёт верхнюю границу для контейнера. <code>quota</code> ограничивает суммарное потребление в области политики. Ни один из этих терминов не является ценой сам по себе.</p>\n<p>Стоимость требует отдельной формулы. В ней могут участвовать базовая плата, объём выделенного ресурса, единица измерения, период, ступени тарифа и дополнительные услуги. Если цена неизвестна, используйте только обозначения. Не подменяйте счёт процентом CPU. Низкая загрузка говорит о наблюдаемом использовании, но не отвечает, какая часть счёта исчезнет после изменения.</p>\n<pre><code>cost(period) = fixed_base\n + allocated_cpu * cpu_rate\n + allocated_memory * memory_rate\n + traffic * traffic_rate\n\ncompare only one changed input\nstop when SLO headroom <= threshold\nstop when the return boundary is unknown</code></pre>\n<p>Код выше — учебная формула. Она не содержит тариф, валюту, скидку или счёт реального проекта. Её задача — показать, какие переменные нужно назвать до арифметики. Если период или единица расходятся, сравнение двух инстансов не имеет смысла.</p>\n<h2>Симптом → причина → проверка → действие</h2>\n<table><caption>Быстрый разбор перед изменением ёмкости</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Причина</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th></tr></thead><tbody><tr><td>Большой инстанс дал лучший p95</td><td>Latency сравнили без стоимости и риска возврата</td><td>Сопоставить SLO headroom, allocation, период и owner</td><td>Не выбирать размер; проверить меньший шаг</td></tr><tr><td>CPU utilisation ниже 40%</td><td>Использование приняли за цену и доступный запас</td><td>Найти billing unit, fixed base и лимиты ресурса</td><td>Не обещать экономию; запросить billing evidence</td></tr><tr><td>В quota ещё есть CPU</td><td>Разрешённый aggregate приняли за доступную ёмкость</td><td>Проверить request, limit, admission и cluster capacity</td><td>Отделить policy-проверку от performance-проверки</td></tr><tr><td>p95 почти достиг SLO</td><td>Следующий шаг хотят выбрать до stop condition</td><td>Вычислить headroom и проверить сигнал очереди</td><td>Остановить ветку и открыть отдельный разбор</td></tr></tbody></table>\n<h2>Пример: три предела на одной шкале</h2>\n<p>Рассмотрим учебные данные для одного workload и 24 часов. У текущего состояния 1,2 CPU, p95 248 ms и условная стоимость 11,424 единицы. Следующий предел поднимает request до 1,4 CPU, даёт p95 248 ms в измеренном окне и условную стоимость 11,856 единицы. Это не доказательство улучшения. Это маленький шаг, в котором изменено ограниченное число входов.</p>\n<p>Вторая точка использует 1,6 CPU. Её p95 равен 296 ms при SLO 300 ms, а сигнал <code>queue-growth</code> показывает рост очереди. Headroom равен 4 ms. Стоимость — 12,288 условной единицы за 24 часа. Ветка останавливается. Ещё больший request не становится объяснением причины очереди.</p>\n<p>Третья точка резервирует 4 CPU и 6 GiB памяти. p95 снижается до 208 ms, а наблюдаемая загрузка CPU составляет 31%. Условная стоимость — 17,76 единицы за 24 часа. Такой результат показывает, что latency можно купить резервом. Он не доказывает, что резерв нужен, что цена рассчитана по реальному тарифу или что его безопасно уменьшить.</p>\n<table><caption>Учебное сравнение трёх вариантов; числа не являются production-измерениями</caption><thead><tr><th scope=\"col\">Вариант</th><th scope=\"col\">Performance</th><th scope=\"col\">Стоимость за 24 ч</th><th scope=\"col\">Риск и решение</th></tr></thead><tbody><tr><td><code>next-limit</code></td><td>p95 248 ms; запас 52 ms</td><td>11,856 u</td><td>low; сравнить следующий малый шаг</td></tr><tr><td><code>saturation-stop</code></td><td>p95 296 ms; запас 4 ms; <code>queue-growth</code></td><td>12,288 u</td><td>stop; сначала выяснить причину сигнала</td></tr><tr><td><code>large-reservation</code></td><td>p95 208 ms; CPU 31%</td><td>17,76 u</td><td>medium; не считать размер базовой стратегией</td></tr></tbody></table>\n<p>Таблица не превращает три оси в общий score. Такой score потребовал бы отдельного владельца и обоснованной формулы. Здесь важнее сохранить отрицательный путь. Если performance хорош, но стоимость или возврат не объяснены, ответом становится остановка. Если стоимость ниже, но SLO почти нарушен, ответом также становится остановка.</p>\n<figure><img src=\"/assets/editorial/2024/capacity-cost-2024-limit-curve.svg\" alt=\"Кривая трёх учебных точек ёмкости: малый следующий предел, граница остановки и большой резерв; линии показывают performance, условную стоимость и операционный риск\" loading=\"lazy\" /><figcaption>Схема разделяет latency, условную стоимость и риск. Она помогает увидеть, где лучший p95 перестаёт быть достаточным основанием для выбора.</figcaption></figure>\n<h2>Почему request, limit и quota не заменяют расчёт</h2>\n<p>Планировщик Kubernetes учитывает requests при размещении Pod. Limit задаёт отдельное ограничение исполнения. ResourceQuota ограничивает суммарные requests или limits в namespace. LimitRange может задать значения по умолчанию и минимальные или максимальные границы на этапе admission. Эти механизмы отвечают на разные вопросы: можно ли принять объект, сколько ресурса он просит и какие пределы действуют. Они не говорят, сколько стоит час работы и выдержит ли сервис нагрузку.</p>\n<p>Поэтому фраза «в quota ещё есть 6 CPU» недостаточна. Она может означать, что объект проходит одну policy-проверку. Она не подтверждает свободную ёмкость кластера, отсутствие конкуренции, нужный запас по SLO или экономический эффект. Сначала проверьте policy. Потом проверьте runtime-сигналы. Затем сопоставьте allocation с разрешённой моделью billing.</p>\n<h2>Остановку нужно определить заранее</h2>\n<p>Stop condition защищает от решения под давлением. Пример правила: остановиться, если запас до SLO меньше 15 ms; остановиться при сигнале роста очереди; остановиться, если новый вариант меняет одновременно CPU, память, класс машины, сеть и concurrency; остановиться, если никто не назвал owner и границу возврата.</p>\n<p>Предел считается следующим только тогда, когда он меняет один основной контролируемый параметр. Для него известны исходное значение, новое значение, период наблюдения и обратная граница. Если вместе с CPU меняются storage, network и commitment, это уже набор решений. Его нельзя объяснить одной строкой «увеличили ёмкость».</p>\n<h2>Порядок действий</h2>\n<ol><li><strong>Зафиксируйте scope.</strong> Назовите workload, окружение, период, SLO, единицы и владельца решения.</li><li><strong>Опишите текущую точку.</strong> Запишите request, limit, quota, p50/p95, error rate, saturation signal и формулу стоимости.</li><li><strong>Назначьте stop condition.</strong> Укажите числовой запас до SLO и сигналы, которые прекращают сравнение.</li><li><strong>Выберите один малый шаг.</strong> Измените один основной параметр и сохраните исходный return boundary.</li><li><strong>Проверьте policy.</strong> Отдельно подтвердите admission, LimitRange, ResourceQuota и возможность размещения.</li><li><strong>Проверьте runtime.</strong> Сравните тот же workload и период по latency, ошибкам, очередям и фактическому использованию.</li><li><strong>Проверьте стоимость.</strong> Подтвердите SKU, usage unit, base unit, ступени тарифа и период. Если данных нет, оставьте стоимость неизвестной.</li><li><strong>Примите ограниченный outcome.</strong> Либо сравните следующий шаг, либо остановитесь с причиной и вопросом владельцу. Большой инстанс не является outcome по умолчанию.</li><li><strong>Зафиксируйте критерий готовности.</strong> Другой инженер должен повторить расчёт и назвать условие остановки без устных пояснений.</li></ol>\n<h2>Ограничения и отрицательный путь</h2>\n<p>Учебные числа в этой статье не описывают конкретный кластер, provider, invoice, telemetry или production workload. Они показывают форму рассуждения. Нельзя переносить 11,856 u, 17,76 u, 31% CPU или p95 208 ms в бюджет и SLO другой системы. Нельзя выводить экономию из разницы между двумя условными суммами.</p>\n<p>Модель также не учитывает автоматически cold start, autoscaling, burst, noisy neighbor, storage, network egress, commitments, скидки, налоги и стоимость сопровождения. Эти факторы могут изменить решение. Если хотя бы один из них влияет на выбор, добавьте его в scope или остановите сравнение.</p>\n<p>Если после изменения сигнал ухудшился, отрицательный путь прост: не скрывайте его усреднением, верните исходную границу только в рамках разрешённого процесса и сохраните причину остановки. Если реальная команда не описала, кто и как выполняет возврат, статья не даёт команды на rollback. Она требует сначала закрыть этот пробел.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Разбор готов к решению, когда одна строка связывает workload, resource allocation, performance signal, billing unit, owner, stop condition и return boundary. Для выбранного шага известны изменяемое поле и период проверки. Policy не смешана с runtime-измерением. Стоимость либо подтверждена официальной формулой и собственными данными, либо явно помечена неизвестной.</p>\n<p>Проверяемый результат — не согласие на самый большой инстанс. Это запись, в которой другой инженер может пересчитать условие, увидеть отрицательную ветку и ответить, почему выбран именно следующий предел. Если он не может назвать, что остановит сравнение, ёмкость ещё не готова к изменению.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\" target=\"_blank\" rel=\"noopener noreferrer\">Kubernetes: Resource Management for Pods and Containers</a> — официально описывает различия requests и limits и их роль при размещении и исполнении.</li><li><a href=\"https://kubernetes.io/docs/concepts/policy/resource-quotas/\" target=\"_blank\" rel=\"noopener noreferrer\">Kubernetes: Resource Quotas</a> — описывает ограничения суммарного потребления в namespace; quota не является счётом и не доказывает доступную ёмкость кластера.</li><li><a href=\"https://docs.cloud.google.com/billing/docs/reference/rest/v1/services.skus/list\" target=\"_blank\" rel=\"noopener noreferrer\">Google Cloud Billing Catalog: services.skus.list</a> — документирует SKU, pricing expression, usage unit, base unit и tiered rates; конкретные цены зависят от сервиса, региона, аккаунта и периода.</li></ul>"
|
||
}
|