Запасы и потоки: почему очередь растёт, а нагрузка та же
Ночной инцидент выглядит так. Дежурному приходит алерт: глубина очереди 12 000 задач вместо обычных двухсот. Он открывает дашборд и видит, что RPS ровно такой же, как вчера и как месяц назад. Ни всплеска трафика, ни новых клиентов. В чате пишут: «нагрузка не менялась, значит проблема не у нас».
Вывод неверный, и ошибка в нём не логическая, а системная. Глубина очереди не обязана следовать за нагрузкой — она следует за разностью между тем, сколько задач приходит, и тем, сколько успевает уходить. Разность может смениться с «плюс десять в секунду» на «минус два» при неизменном притоке. Через час это минус два превращается в 7 200 задач, которые сами никуда не денутся.
В предыдущей главе мы разобрали, как связи замыкаются в петли. Теперь нужен второй элемент языка: что именно накапливается внутри петли. Без него причинные схемы остаются стрелочками без величин; с ним появляются числа, прогнозы и способ проверить, не врёте ли вы себе.
Два вида величин, которые постоянно путают
Запас (stock) — то, что можно измерить в один момент, сфотографировав систему. Остановите мир — запас останется. Поток (flow) — скорость изменения запаса. Остановите мир — поток обратится в ноль, потому что поток существует только во времени.
Правило размерности — самый дешёвый тест
У запаса размерность «штука». У потока — «штука в единицу времени». Отсюда правило, которое ловит бо́льшую часть путаницы на планёрках:
Если к названию метрики можно осмысленно добавить «в секунду» или «в неделю» и смысл не сломается — это поток. Если нельзя — это запас.
- «Закрыли 30 багов за спринт» — поток. «У нас 400 открытых багов» — запас.
- «Velocity 45 story points» — поток. «Бэклог 900 story points» — запас.
- «Наняли пятерых» — поток. «В команде 23 инженера» — запас.
Отсюда сразу следует вывод, экономящий много бессмысленных обсуждений: рост потока «закрытия» ничего не говорит о запасе, пока вы не знаете поток «открытия». Команда, закрывающая 30 багов в спринт при 35 приходящих, на дашборде выглядит героической, а на графике запаса — проигрывающей.
Что бывает запасом в инженерной системе
| Слой | Запас (штуки) | Приток | Отток |
|---|---|---|---|
| Инфраструктура | глубина очереди | публикация задач | обработка воркерами |
| Инфраструктура | лаг репликации, байты | запись на мастере | применение на реплике |
| Инфраструктура | занятые соединения пула | открытие соединения | освобождение, таймаут |
| Хранение | занятое место на диске | запись логов, дампы | ротация, TTL, архивация |
| Процесс | незакрытые баги | заведение | исправление, закрытие как неактуальных |
| Процесс | открытые pull request | создание PR | мерж, закрытие |
| Люди | обученные дежурные | онбординг, тренировки | уход, выгорание, переход |
| Скрытые | технический долг | компромиссные решения | рефакторинг |
| Скрытые | доверие пользователей | удачные релизы | инциденты, откаты |
Обратите внимание на две нижние строки. Техдолг и доверие ведут себя как запасы (накапливаются, инерционны, медленно расходуются), но прямо не измеряются. Мы вернёмся к ним в разделе про пределы метода — именно здесь системное мышление чаще всего скатывается в бессодержательные схемы.
Главное уравнение: запас — это накопленная разность
Всё поведение запаса описывается одной строкой:
L(t + Δt) = L(t) + (λ − μ) · Δt # λ — приток, μ — отток, оба в «задачах в секунду»
Запас — это интеграл разности потоков. Три следствия, которые упорно игнорируют:
- Уровень зависит не от величины потоков, а от их разности. Приток 10 000 задач/с при оттоке 10 000 даёт стабильную очередь; приток 10 при оттоке 8 — растущую.
- Запас нельзя изменить мгновенно. Даже если обнулить приток прямо сейчас, накопленное придётся вычерпывать оттоком. Отсюда задержки, которым посвящена следующая глава.
- Запас помнит прошлое. Кратковременное превышение притока оставляет след, который не рассасывается сам при возврате к паритету.
Почему интуиция ломается систематически
Это не «люди невнимательны», а воспроизводимый экспериментальный результат. Cronin, Gonzalez и Sterman («Why don’t well-educated adults understand accumulation?», OBHDP, 2009, doi:10.1016/j.obhdp.2008.03.003) давали студентам MIT и Гарварда простейшую задачу: графики входящего и исходящего потока людей в магазине, вопрос — как менялось число людей внутри. Правильно отвечало меньше половины, и результат не улучшался ни от подсказок, ни от математической подготовки, ни от смены формата графика.
Типичная ошибка — «сопоставление формы»: испытуемые рисовали график запаса, повторяющий форму графика потока. Ровно та же ошибка, что у дежурного из вступления.
Практический вывод: не рассчитывайте, что участники инцидента правильно прочитают графики потоков. Выводите отдельную панель с запасом и отдельную панель с разностью потоков. Это не украшательство дашборда, а компенсация известного когнитивного дефекта.
Возвращаемся к загадке: пять причин роста при неизменном притоке
Приток постоянен — 100 задач/с всё время. На третьей минуте отток проседает со 110 до 98, на двенадцать процентов, что легко пропустить глазом. Пять минут спустя в очереди 600 задач. Верхний график почти плоский, нижний вырос от нуля до пика: маленькая разность, помноженная на время, даёт большой запас.
Откуда просадка оттока при том же притоке:
- Деградация зависимости. База отвечает не за 40 мс, а за 400 — воркер обрабатывает меньше задач в секунду при том же их числе.
- Изменился состав нагрузки. RPS тот же, но доля тяжёлых запросов выросла с 5 % до 15 %. Средняя стоимость запроса — невидимый на графике RPS множитель между нагрузкой и потребной ёмкостью.
- Появился конкурент за общий ресурс. Соседний сервис занял пул соединений, батч-джоба съела IOPS. Ваша нагрузка не менялась — менялась доступная вам ёмкость.
- Уменьшилось число обработчиков. Автоскейлер откатился, под выселили. Классика: «мы ничего не деплоили» при том, что откатился HPA.
- Приток вырос не там, где вы смотрите. Клиентские таймауты породили ретраи: пользователей столько же, запросов больше. Вы измеряете поток через не ту границу — вопрос из главы о границах.
Формула разгребания и главная ошибка восстановления
время разгребания = L / (μ − λ)
Накоплено 600 задач. Восстановили отток до 110 — разность 10, разгребание 60 секунд. До 104 — разность 4, разгребание 150 секунд. До 100, то есть ровно до паритета с притоком, — разность ноль, очередь не разгребается никогда, она просто перестаёт расти.
Последний случай — самая частая ошибка постинцидентных решений. Метрика «отток равен притоку» выглядит здоровой, дашборд зелёный, а 600 задач продолжают ждать, и p99 остаётся кошмарным ещё несколько часов. Сигнал тревоги из системы ушёл, запас остался.
Восстановление после накопления требует избыточной пропускной способности, а не равной. Если вы не можете назвать разность
μ − λпосле починки — вы не знаете, разгребётся ли очередь вообще.
Отсюда следует, на что алертить. Порог «глубина больше 1000» срабатывает и в безобидном случае, и в катастрофическом. Алерт на прогнозируемое время разгребания различает их сразу:
groups:
- name: stock-and-flow
rules:
# потоки — производные счётчиков, размерность «задач в секунду»
- record: job:inflow:rate5m
expr: rate(jobs_enqueued_total[5m])
- record: job:outflow:rate5m
expr: rate(jobs_dequeued_total[5m])
# чистый поток: положительный означает, что запас растёт
- record: job:net_flow:rate5m
expr: job:inflow:rate5m - job:outflow:rate5m
# независимая оценка запаса по счётчикам
- record: job:level_from_flows
expr: jobs_enqueued_total - jobs_dequeued_total
# расхождение с прямым замером — сигнал о потерях или невидимом притоке
- record: job:level_drift
expr: queue_depth - job:level_from_flows
- alert: QueueDrainTimeTooLong
# clamp_min не даёт делить на ноль и на отрицательное
expr: queue_depth / clamp_min(-job:net_flow:rate5m, 0.001) > 1800
for: 10m
annotations:
summary: "Очередь разгребётся дольше 30 минут при текущих потоках"
Про ограничения rate см. документацию Prometheus, про алертинг по симптомам — SRE Workbook. Трек по надёжности на портале ещё в работе; смежные практики наблюдаемости разобраны в DevOps и распределённых системах.
Закон Литтла: мост между запасом и потоком
Есть ровно одна формула, связывающая запас, поток и время ожидания, и она удивительно устойчива:
L = λ · W # L — среднее число единиц в системе, λ — интенсивность прибытия, W — время в системе
Доказана Джоном Литтлом в 1961 году («A Proof for the Queuing Formula», Operations Research, doi:10.1287/opre.9.3.383) без предположений о распределениях, дисциплине обслуживания и числе серверов. Условия всё же есть: система наблюдается достаточно долго и стационарна; всё вошедшее в итоге выходит (нет потерь); L, λ и W измерены на одной границе.
Практический приём: три независимых замера запаса
Именно потому, что закон почти не требует предположений, он работает как детектор ошибок измерения. Глубину очереди можно получить тремя способами: прямо (queue_depth из брокера), из потоков (enqueued_total − dequeued_total) и через Литтла (λ из счётчика прибытий, W из гистограммы, L = λ · W). Если три оценки сходятся — модель верна. Если нет, расхождение диагностично:
- прямой замер меньше оценки по потокам → часть задач теряется (дропы по TTL, переполнение буфера, проглоченные исключения);
- прямой замер больше → есть невидимый приток (ретраи, дублирующий продюсер, задачи, которые порождают сами воркеры);
- Литтл даёт
W = 6 с, а трассировка показываетp50 = 0.4 с→ вы измеряете не ту очередь: трассировка начинается после извлечения из брокера и не видит ожидания.
Если готовой метрики запаса нет, его восстанавливают из журнала событий:
-- Поток — сумма дельт за интервал; запас — накопительная сумма потоков.
WITH events AS (
SELECT ts, +1 AS delta FROM queue_log WHERE kind = 'enqueue'
UNION ALL
SELECT ts, -1 AS delta FROM queue_log WHERE kind = 'dequeue'
),
per_minute AS (
SELECT date_trunc('minute', ts) AS minute,
SUM(delta) AS net_flow -- поток, задач в минуту
FROM events
GROUP BY 1
)
SELECT minute,
net_flow,
SUM(net_flow) OVER (ORDER BY minute) AS level -- запас, задач
FROM per_minute
ORDER BY minute;
Оконная накопительная сумма здесь — буквально численное интегрирование потока, то же самое, что делает сама система, только задним числом.
Симуляция: тридцать строк вместо спора
Спорить, «успеем ли разгрести к утру», бессмысленно, когда можно посчитать. Минимальная модель запаса — цикл Эйлера.
уровень ← 0
для каждого шага dt:
доступно ← уровень + приток(t) · dt
обслужено ← min(ёмкость(t) · dt, доступно) # больше, чем есть, обслужить нельзя
уровень ← доступно − обслужено
если уровень > предел_буфера: # переполнение даёт потери
потеряно ← уровень − предел_буфера
уровень ← предел_буфера
"""Очередь как резервуар: приток, ограниченный отток, необязательный предел буфера."""
from typing import Callable, Optional
LAMBDA = 100.0 # задач/с, не меняется весь эксперимент
DEGRADED_FROM, DEGRADED_TO = 180.0, 480.0 # деградация с 3-й по 8-ю минуту
def simulate(duration_s: float, dt: float,
inflow: Callable[[float], float],
service: Callable[[float], float],
capacity: Optional[float] = None) -> list[tuple]:
"""Возвращает историю (t, уровень, потери). Все ставки — задач/с, dt — секунды."""
level, dropped_total, t, history = 0.0, 0.0, 0.0, []
while t < duration_s:
available = level + inflow(t) * dt # задач
level = available - min(service(t) * dt, available)
if capacity is not None and level > capacity:
dropped_total += level - capacity
level = capacity
history.append((t, level, dropped_total))
t += dt
return history
def make_service(recovered_rate: float) -> Callable[[float], float]:
"""Ёмкость: 110 задач/с → 98 на время инцидента → recovered_rate после починки."""
def service(t: float) -> float:
if DEGRADED_FROM <= t < DEGRADED_TO:
return 98.0
return 110.0 if t < DEGRADED_FROM else recovered_rate
return service
if __name__ == "__main__":
for recovered in (110.0, 104.0, 100.0):
hist = simulate(1800, 0.5, lambda t: LAMBDA, make_service(recovered))
peak = max(row[1] for row in hist)
drained = next((row[0] for row in hist
if row[0] > DEGRADED_TO and row[1] < 1.0), None)
when = f"{drained - DEGRADED_TO:.0f} с" if drained else "не разгреблась за 30 мин"
print(f"μ после починки {recovered:5.0f} | пик {peak:5.0f} задач | разгребание: {when}")
μ после починки 110 | пик 600 задач | разгребание: 60 с
μ после починки 104 | пик 600 задач | разгребание: 150 с
μ после починки 100 | пик 600 задач | разгребание: не разгреблась за 30 мин
Сложность. Время O(T / dt) — линейно по числу шагов и не зависит от величины запаса. Память O(T / dt) из-за истории; если считать пик и время разгребания на лету — O(1). Для модели из n связанных запасов (очередь → воркеры → БД → очередь ретраев) время становится O(n · T / dt), что для десятков запасов и часов модельного времени — доли секунды.
Выбор шага. У метода Эйлера накопленная ошибка порядка O(dt). Практическое правило: dt заметно меньше самого короткого характерного времени системы (длительности ступеньки, времени реакции автоскейлера, периода опроса). Если результат меняется при уменьшении dt вдвое — шаг слишком крупный. Подробности — в численных методах.
Что эта модель не покажет
Здесь начинается честная часть. Модель детерминированная и усреднённая, она не знает про дисперсию. А очередь — объект, у которого дисперсия важнее среднего:
- при загрузке
ρ = λ / μ, близкой к единице, среднее ожидание растёт какρ / (1 − ρ), то есть взрывообразно; модель по средним даст оптимистичный ответ там, где реальность уже развалилась; - всплески притока с одинаковым средним, но разной «пачечностью» дают радикально разные пики запаса;
- при
ρ > 1очередь растёт линейно и предсказуемо, а вот околоρ = 1поведение чувствительно к мелочам и точность модели резко падает.
Вывод: усреднённая stock-and-flow модель хороша для вопросов «успеем ли разгрести», «когда кончится диск», «на сколько поднять ёмкость». Она плоха для вопроса «какой будет p99» — там нужны распределения (см. вероятность и статистику и нагрузочное тестирование). Переход от «чуть больше нагрузки» к «другой режим» разбирается в главе о нелинейности.
Как запасы попадают в петли
Запас сам по себе пассивен. Проблемы начинаются, когда его уровень влияет на потоки — то есть когда запас оказывается внутри петли обратной связи.
(ЗАПАС)"] W["Время ожидания W"] TO["Клиентские таймауты"] RT["Ретраи"] IN["Приток λ
(ПОТОК)"] OUT["Отток μ
(ПОТОК)"] AS["Число воркеров"] SHED["Сброс нагрузки"] IN -->|"+"| L L -->|"+"| W W -->|"+"| TO TO -->|"+"| RT RT -->|"+"| IN L -->|"+"| AS AS -->|"+"| OUT OUT -->|"−"| L W -->|"+"| SHED SHED -->|"−"| IN classDef stock fill:#5b8def33,stroke:#4a90d9,stroke-width:2px classDef flow fill:#d9804033,stroke:#d98040,stroke-width:2px class L stock class IN,OUT flow
Три контура на одной картинке:
- Усиливающий:
L → W → таймауты → ретраи → λ → L. Отрицательных связей ноль, число чётное — петля разгоняет сама себя. Именно она превращает двенадцатипроцентную деградацию в полный отказ. - Уравновешивающий:
L → число воркеров → μ → L. Одна отрицательная связь — петля сопротивляется росту, но реагирует с задержкой. - Уравновешивающий:
W → сброс нагрузки → λ → L. Работает быстро, ценой отказов части клиентов.
Правило подсчёта знаков разбиралось в главе о петлях: нечётное число отрицательных связей даёт уравновешивающую петлю, чётное — усиливающую.
Вот как усиливающая петля выглядит в динамике одного запроса:
Кульминация в последней строке: ретраи не только увеличивают приток, но и уменьшают полезный отток. Обе стрелки петли работают в одну сторону. Противоядия — экспоненциальная задержка с джиттером, бюджет ретраев, circuit breaker — разобраны в паттернах устойчивости и в главе Handling Overload из Google SRE Book.
Режимы, в которых живёт запас
Состояние Saturated — отдельная ловушка наблюдаемости: график глубины становится идеально плоским на уровне лимита, и неопытный глаз читает это как «стабилизировалось». Различить помогает только счётчик дропов или расхождение job:level_drift из рецепта выше.
Типовые ловушки запасов и потоков
Полный каталог архетипов будет в главе 09; здесь только те, что вырастают прямо из путаницы запаса и потока.
1. Управление потоком при растущем запасе. Команда отчитывается по velocity, менеджер радуется её росту, бэклог растёт. Метрика потока улучшается, метрика запаса ухудшается, и обе правдивы. Лечение: любой отчёт о потоке обязан сопровождаться отчётом о запасе и разности. Про подбор таких метрик — продуктовые метрики.
2. Локальная оптимизация притока. Ускорили ingest впятеро — «оптимизировали сервис». Пропускная способность обработки не менялась, запас теперь растёт впятеро быстрее, инцидент случается раньше. Диагностический вопрос: «эта оптимизация увеличивает приток, отток или ни то ни другое?» Подробный разбор — в главе 10.
3. Перенос проблемы: увеличить буфер вместо ёмкости. Очередь переполняется — подняли лимит с 10 000 до 1 000 000. Дропы исчезли, алерт замолчал. На самом деле запас теперь может вырасти в сто раз больше, а значит по закону Литтла и время ожидания тоже. Явные отказы обменяли на скрытую задержку, которая проявится как жалобы «иногда всё висит», а гигантский буфер замаскирует нехватку ёмкости на месяцы. Это архетип «перенос проблемы»: симптоматическое решение снимает давление, которое привело бы к фундаментальному.
4. Эскалация через ретраи. Признак: приток растёт как функция собственной задержки системы. Проверяемая гипотеза — «доля ретраев в притоке во время инцидента выше базовой». Она измеряется, если ретраи помечены заголовком или атрибутом трассировки; если не помечены, вы не отличите рост нагрузки от самоусиления. Дешёвое улучшение наблюдаемости с высокой отдачей.
5. Трагедия общего ресурса. Общий пул соединений, общий CI-кластер, общая квота. Каждая команда локально права, увеличивая своё потребление; общий запас доступной ёмкости истощается. Признак архетипа: запас разделяемый, потоки индивидуальные, обратная связь приходит ко всем сразу и с задержкой. Инженерные лечения — квоты, изоляция (bulkhead), приоритеты; организационные — сделать потребление видимым по командам.
6. Костыль, вокруг которого вырос процесс. Однажды написали скрипт, который ночью вручную разгребает застрявшую очередь. Через год есть дежурство «на разгребалке», пункт в онбординге и заложенное в SLA время её работы, а первопричина застреваний давно не расследуется. Запас неисправленных причин растёт, давление на его исправление обнулено. Системный взгляд даёт здесь конкретное действие: измерять частоту применения костыля как поток и алертить на её рост, а не на сам факт застревания.
Откуда взялся этот язык и что о нём известно
Хорошо подтверждено:
- Люди систематически ошибаются в задачах на накопление — многократно воспроизведено на разных выборках и форматах. Сильный аргумент за то, чтобы явно выводить запасы на дашборды.
- Эффект хлыста в цепях поставок существует и измеряется. Lee, Padmanabhan и Whang (Sloan Management Review, 1997) показали его на реальных данных и связали с задержками и локальными правилами заказа. Инженерный аналог — раскачка автоскейлера, реагирующего на устаревшую метрику.
- Закон Литтла — доказан математически и проверяем прямым измерением.
Остаётся спорным:
- Агрегированные глобальные модели. «Пределы роста» (1972) с моделью World3 — самый известный и самый оспариваемый пример. Уильям Нордхаус в рецензии «World Dynamics: Measurement Without Data» (The Economic Journal, 1973, doi:10.2307/2230167) указал на главную слабость: коэффициенты связей задавались из общих соображений, а не оценивались по данным, поэтому модель нельзя ни подтвердить, ни опровергнуть статистически. Поздние сверки сценариев с фактическими данными (Herrington, Journal of Industrial Ecology, 2021, doi:10.1111/jiec.13084) показывают совпадение по ряду переменных, но это ретроспективная сверка, а не проверка предсказаний вне обучающей выборки.
- Модели «мягких» переменных. Стрелка «мораль команды → производительность» может быть верной по сути, но без единиц измерения и оценённого коэффициента она не предсказывает ничего.
Здоровая позиция: доверяйте модели пропорционально измеримости её переменных и проверяемости её предсказаний на коротком горизонте. Сам Sterman писал об этом честнее многих популяризаторов — см. «All models are wrong» (System Dynamics Review, 2002, doi:10.1002/sdr.261).
Пределы метода: где схема начинает врать
Правый верхний квадрант — то, ради чего стоит рисовать модель: переменные измеримы, предсказание проверяется за смену. Левый нижний — зона, где системные схемы вырождаются в декорацию. Это не значит, что про техдолг нельзя думать системно; это значит, что модель техдолга без прокси-метрики (доля времени на исправления, время прохождения CI, время до первого коммита новичка) — не модель, а метафора.
Красные флаги схемы
- У стрелки нет величины. Нельзя назвать, что течёт и в каких единицах — стрелка не проверяема.
- Запас и поток нарисованы одинаково. Если «баги» и «исправление багов» — узлы одного вида, автор не различает уровень и скорость.
- Нет ни одного числа. Модель без порядков величин не отличает «через час» от «через год».
- Границы не заданы — значит потоки измеряются как попало (см. главу 02).
- Нет предсказания, которое может не сбыться. Если из схемы не следует ничего опровержимого наблюдением, это описание, а не модель. Критерии подробно разбираются в научном и инженерном рассуждении.
- Модель объясняет что угодно постфактум — признак подгонки, а не понимания.
Что реально можно проверить за неделю
- Баланс потоков. Приток минус отток за период должен равняться изменению запаса. Расхождение больше пары процентов — утечка, невидимый источник или ошибка измерения. Бухгалтерская сверка, которая почти всегда что-нибудь находит.
- Прогноз исчерпания. «При росте на 12 ГБ в сутки диск заполнится через 9 дней» — проверяется через 9 дней.
- Прогноз разгребания. «Отток 104, приток 100, накоплено 600 — разгребёмся за 150 секунд» — проверяется на следующем инциденте.
- Сверка по Литтлу. Три независимых замера должны сойтись.
- Реакция на воздействие. «Добавим двух воркеров, отток вырастет на 20, очередь уйдёт за 30 секунд» — эксперимент, который ставится в рабочее время.
Если ни одна проверка к вашей схеме неприменима, вы в левой части квадранта и обязаны честно пометить модель как гипотезу.
Мини-практикум
- Разметьте дашборд. Выпишите десять метрик, которые смотрите чаще всего, и отнесите каждую к запасам или потокам. Найдите запас без соответствующего потока и поток без запаса — они почти наверняка есть.
- Посчитайте время разгребания. Возьмите последний инцидент с очередью: пик, приток и отток после починки. Сходится ли расчёт с фактом? Если нет — где потерялся поток?
- Сверьте три оценки запаса (gauge, разность счётчиков,
λ · W). Расхождение — готовая тема для расследования. - Найдите буфер, который вырос вместо ёмкости (лимит очереди, размер пула, TTL задачи). Что стало с временем ожидания после того, как его подняли?
- Опишите процессный запас числом. Постройте два графика по багам: поток заведения и поток закрытия. Что накопится за квартал при текущей разности?
Мини-итог
- Запас измеряется в штуках и существует в моменте; поток — в штуках за время и существует только в интервале. Правило «добавь в секунду» различает их за пару секунд.
- Запас — накопленная разность потоков, поэтому его график не повторяет форму графиков потоков. Человеческая интуиция здесь ошибается системно, а не случайно.
- Очередь растёт при неизменной нагрузке минимум по пяти причинам, и четыре из них относятся к оттоку.
- Восстановление до паритета потоков не разгребает накопленное. Нужна избыточная ёмкость; алертить полезнее на время разгребания, чем на глубину.
L = λ · W— самая надёжная связь между запасом и потоком и одновременно детектор ошибок измерения при сверке трёх независимых оценок.- Простая модель отвечает на вопросы про средние и не отвечает на вопросы про хвосты. Знать эту границу важнее, чем усложнять модель.
- Метод проверяем ровно настолько, насколько измеримы его переменные. Где измерить нечем — пишите «гипотеза» и ищите прокси-метрику.
Источники
- Forrester J. W. Industrial Dynamics: A Major Breakthrough for Decision Makers // Harvard Business Review, 1958. hbr.org
- Forrester J. W. Industrial Dynamics. MIT Press, 1961 — первоисточник языка запасов и потоков.
- Little J. D. C. A Proof for the Queuing Formula L = λW // Operations Research, 1961. doi:10.1287/opre.9.3.383
- Little J. D. C., Graves S. C. Little’s Law // Building Intuition, Springer, 2008. springer.com
- Sterman J. D. Business Dynamics. McGraw-Hill, 2000 — учебник с разделами о валидации моделей.
- Sterman J. D. All models are wrong // System Dynamics Review, 2002. doi:10.1002/sdr.261
- Cronin M. A., Gonzalez C., Sterman J. D. Why don’t well-educated adults understand accumulation? // OBHDP, 2009. doi:10.1016/j.obhdp.2008.03.003
- Meadows D. Thinking in Systems: A Primer. Chelsea Green, 2008 — доступное введение, но проверяйте утверждения на своих данных.
- Nordhaus W. D. World Dynamics: Measurement Without Data // The Economic Journal, 1973. doi:10.2307/2230167 — обязательный противовес.
- Herrington G. Update to limits to growth // Journal of Industrial Ecology, 2021. doi:10.1111/jiec.13084
- Lee H. L., Padmanabhan V., Whang S. The Bullwhip Effect in Supply Chains // Sloan Management Review, 1997. sloanreview.mit.edu
- Google SRE Book, Handling Overload. sre.google
- Nygard M. Release It! 2nd ed. Pragmatic Bookshelf, 2018 — bulkhead, circuit breaker, backpressure.
- Vacanti D. Actionable Agile Metrics for Predictability, 2015 — закон Литтла для потока задач.
Что дальше
Мы разобрали, как запас накапливает разность потоков, и несколько раз упёрлись в одно осложнение: реакция системы приходит не сразу. Автоскейлер видит устаревшую метрику, найм даёт эффект через полгода, последствия архитектурного решения проявляются через год. Задержка между воздействием и результатом превращает даже простую уравновешивающую петлю в колебательную систему, которая раскачивается тем сильнее, чем энергичнее её пытаются стабилизировать.