В одном tabletop-разборе лежат три fixed synthetic cards. Первая держит 1,4 CPU, p95 248 ms и low operational risk. Вторая поднимается до 1,6 CPU, но p95 уже 296 ms и signal queue-growth. Третья сразу выбирает 4 CPU, получает p95 208 ms и observed CPU 31%. Симптом встречи знакомый: участники хотят перейти от второй карточки к третьей, потому что она «самая быстрая». Цена ошибки — пропустить stop condition, перепутать performance с безопасностью и назвать большой reservation единственным способом убрать тревогу.
Полевая задача уже: не подобрать instance, а выбрать следующий предел, который можно объяснить тремя осями — performance, model cost и operational risk. Причина выбора по максимальному размеру в том, что одна хорошая цифра p95 заслоняет resource contract и return boundary. Проверка должна сравнить cases по одинаковому scope и периоду, назвать stop condition до действия и отделить teaching return card от реального rollback. Действие будет либо compare-next-synthetic-limit, либо stop и human review; fixture не создаёт третьего пути.
Три сценария как материал полевого разбора
Первый сценарий — next limit. next-limit-balanced содержит 1,4 CPU request, 1,8 CPU limit, 2,2 GiB memory и p95 248 ms при SLO 300 ms. Его model cost за 24 часа равен 11,856 u. CPU observed 67%, saturation помечена как watch, а operational risk — low. Fixture позволяет сравнить следующий fixed limit 1,6 CPU и фиксирует delta 0,384 u/24h. Это не рекомендация увеличить request: это единственная карточка, где учебная логика ещё не встретила stop.
Второй сценарий — stop. saturation-stop использует 1,6 CPU request и 2 CPU limit, однако p95 оставляет лишь четыре миллисекунды headroom, а signal уже равен queue-growth. Cost равна 12,288 u/24h, но разница цены не главный факт. Модель останавливается по p95 boundary и просит отдельный review. Ошибка была бы в том, чтобы назвать quota 6 CPU запасом, который автоматически лечит очередь. Quota здесь только допустимая абсолютная граница, а не доказательство поведения следующего limit.
Третий сценарий — большой reservation. large-instance-unjustified задаёт 4 CPU request и 6 GiB memory, поэтому p95 падает до 208 ms. Но observed CPU 31%, model cost равна 17,76 u/24h, а operational risk остаётся medium: в модели не доказано, какой change был безопасен и как его вернуть. Fixture не говорит «уменьшить до 1,4». Она возвращает stop-and-compare-smaller-synthetic-limit. Достаточно этого отрицательного результата: большой instance не получает статус базовой стратегии только потому, что одна latency-точка лучше.
Матрица выбора: не один лучший показатель
| Scenario | Performance | Model cost / 24h | Operational risk | Fixture outcome |
|---|---|---|---|---|
next-limit-balanced | p95 248 ms; headroom 52 ms | 11,856 u; next CPU delta 0,384 u | low; saturation watch | compare-next-synthetic-limit |
saturation-stop | p95 296 ms; headroom 4 ms; queue-growth | 12,288 u | medium; performance boundary unclear | stop-and-review-synthetic-limit |
large-instance-unjustified | p95 208 ms; observed CPU 31% | 17,76 u | medium; return safety not proven | stop-and-compare-smaller-synthetic-limit |
Матрица не складывает три колонки в score. Это было бы ещё одной скрытой formula без owner-а. Её задача проще: не позволить одной колонке отменить другую. У третьего case лучше p95, но он не объясняет marginal effect между 1,6 и 4 CPU и не имеет доказанного operational path. У второго case нет самого большого cost, но его p95/risk condition уже достаточна для stop. У первого нет успеха; есть только ограниченное право продолжить учить модель на следующем fixed limit и перенести real decision владельцу.
Сначала stop condition, потом следующий предел
Stop condition должна быть записана до сравнения вариантов. В fixture есть три вида. p95-headroom-at-or-below-15ms останавливает scenario, где latency почти касается SLO. saturation-signal-present остановил бы case с очередью даже при другом запасе p95. large-reserve-with-low-observed-utilisation не говорит, что ресурс точно лишний; он запрещает использовать большой reservation как ответ без сравнения меньшего fixed step. Эти условия не равны production policy. Они намеренно узкие и понятные как unit-test reasoning.
Затем формулируется next limit. Он должен отличаться одним основным контролируемым полем и иметь return point. В next-limit-balanced следующая карта меняет CPU request с 1,4 до 1,6 и CPU limit с 1,8 до 2; return point хранит исходные 1,4 и 1,8 как teaching record. Memory, period и unit здесь фиксированы. Если в реальном обсуждении вместе с CPU меняют class instance, network, concurrency, storage и commitment, это уже не «следующий предел». Это несколько решений, для которых одной линейной карточки недостаточно.
Компактный прогон decision и return boundary
Пример ниже строит report, затем decision draft и return card для next-limit-balanced. Return card существует только после canonical report и только для branch без stop. Она содержит фразу does-not-change-a-workload-or-prove-a-real-rollback. Такая формулировка нужна, чтобы во время напряжённого разбора никто не перепутал зафиксированную точку возврата с командой к API. Файл не импортирует cloud client и не знает имя cluster, manifest, namespace, account или deployment.
import {
createFixedSyntheticCapacityInput,
inspectSyntheticCapacityCost,
planSyntheticCapacityDecision,
draftSyntheticCapacityRollback,
} from './upgrade-2024-10.mjs';
const report = inspectSyntheticCapacityCost(
createFixedSyntheticCapacityInput('next-limit-balanced'),
);
const draft = planSyntheticCapacityDecision(report);
const returnCard = draftSyntheticCapacityRollback(draft);
console.log({ decision: draft.decision, returnCard: returnCard.reason });
Проверка fixture покрывает не только happy case. Если в report изменить cost, добавить billingExport, передать sparse nested array или получить cyclic object, plan отвергается. Если в draft изменить actions или добавить field, похожий на cloud command, return card тоже не создаётся. Эти assertions не делают rollback безопасным в production. Они доказывают лишь узкое правило: учебный record не должен принять мутировавший object как разрешение на действие. Для темы capacity это важнее красивого примера с одной зелёной веткой.
Роль quota и limit в полевом маршруте
Quota и limit находятся рядом с выбором, но не заменяют его. Kubernetes ResourceQuota позволяет ограничивать aggregate requests и limits в namespace, но не превращает разрешённый aggregate в доступную ёмкость кластера. LimitRange может применить default/min/max на admission и не пересобирает уже существующие workload. Поэтому field reviewer сначала спрашивает: пройдёт ли новая форма policy? Затем: какой resource она резервирует? Потом: какую billing formula мы вообще собираемся сопоставить? И только после этого — какое performance evidence допустимо сравнить. Перестановка вопроса «а quota позволяет?» на конец обсуждения создаёт лишний риск уже на стадии формы.
В synthetic cards quota 6 CPU одна и та же. Это сделано специально: она не становится объяснением разницы между 1,4 и 4 CPU. Если держать quota одинаковой, видно, что performance, cost и operational risk меняются не из-за самой quota. В реальном контуре quota может быть важной policy, но она не превращает capacity change в harmless change. У неё собственный owner, admission semantics и blast radius. Статья не выдаёт учебный literal за готовое правило namespace.
Маршрутизированный чек-лист полевого разбора
- Старт: зафиксируйте case. Выберите один workload, один период и одну formula. Если карточка смешивает разные units или scope, маршрут заканчивается до сравнения.
- Ветка performance. Запишите p95, SLO и headroom. При заданном stop condition не переходите к размеру instance; сформулируйте недостающий authorised measurement.
- Ветка resource policy. Проверьте request, limit, quota и admission constraint. Ответ «quota ещё есть» не закрывает performance или cost branch.
- Ветка cost model. Отделите fixed base, variable allocation, unit и period. Если unit не подтверждена источником, не вычисляйте marginal effect.
- Ветка operational risk. Назовите owner, допустимый scope и return boundary. Если return означает непонятное действие над workload, останьтесь в review.
- Финиш: выберите outcome. Только
compare-next-synthetic-limitведёт к новой учебной карточке. Любой stop ведёт к отдельному human question, а не к большому instance.
Ограничения и следующий проверяемый шаг
Ни один case не является нагрузочным тестом, cloud quote, счётом, telemetry snapshot, анализом scheduler, интервью или incident report. Все request, limit, quota, rates, request/s, p95, risk labels и return points — fixed versioned JS literals. Модель не знает, как реальный runtime использует CPU, как provider применяет commitment/tier/discount, какие dependencies находятся за latency и кто уполномочен менять capacity. Поэтому она не заявляет cost saving, не выбирает provider и не советует реальный rollback.
Следующий проверяемый шаг — пройти таблицу втроём на бумаге. Первый читает только performance column, второй — только cost model, третий — только resource/operational column. Каждый обязан назвать одну stop condition или недостающий источник. Затем группа выбирает один из трёх outcomes fixture и сверяет, нет ли решения, основанного на единственной колонке. Успех — короткая доказуемая причина остановки или следующего synthetic limit, а не согласие на самый большой instance.
Историческая граница октября 2024
Источники в конце закреплены датами марта–июня 2024 и существовали до конца октября 2024. Kubernetes docs поддерживают различение request, limit, quota и admission constraints. Google API proto поддерживает различение usage/base unit и tiered rate в billing expression. Три scenarios, cost values, stop conditions, decisions и return cards принадлежат только synthetic-capacity-cost-model/2024-10-v1. Они не описывают неизвестный production и не исполняют никаких действий.
Проверяемые источники
- Kubernetes documentation: Resource requests and limits, immutable snapshot 06.05.2024 — Первичный неизменяемый снимок документации Kubernetes. Он подтверждает, что scheduler учитывает request, а CPU/memory limit имеют отдельную семантику исполнения. Он не задаёт цену ресурса, модель счёта или удачный размер instance.
- Kubernetes documentation: ResourceQuota, immutable snapshot 30.05.2024 — Первичный неизменяемый снимок документации Kubernetes. Он подтверждает абсолютные quota для requests и limits; сумма quota может превышать ёмкость кластера, поэтому quota не является обещанием доступной capacity. Он не связывает quota с облачным invoice и не доказывает, что quota снижает расход.
- Kubernetes documentation: LimitRange, immutable snapshot 14.03.2024 — Первичный неизменяемый снимок документации Kubernetes. Он описывает default, minimum, maximum и ratio request/limit на admission stage. Он не является прогнозом saturation, цены или поведения уже запущенного workload.
- Google Cloud Billing Catalog v1 proto, immutable snapshot 18.06.2024 — Первичный неизменяемый API-contract. В нём определены SKU, pricing expression, usage unit, base unit и tiered rates. Он объясняет форму billing formula, но не сообщает тариф, валюту, скидку или счёт конкретного читателя.