Files
progcode/editorial/agent-rewrites/115.json
T
huncode 2d914b543f
Build and deploy / deploy (push) Failing after 15s
Publish rewritten technical article archive
2026-08-02 22:19:34 +03:00

8 lines
18 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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>"
}