惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
博客园 - 叶小钗
酷 壳 – CoolShell
酷 壳 – CoolShell
Apple Machine Learning Research
Apple Machine Learning Research
云风的 BLOG
云风的 BLOG
量子位
博客园 - 三生石上(FineUI控件)
Stack Overflow Blog
Stack Overflow Blog
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
人人都是产品经理
人人都是产品经理
V
Visual Studio Blog
Jina AI
Jina AI
L
LangChain Blog
M
MIT News - Artificial intelligence
MongoDB | Blog
MongoDB | Blog
Last Week in AI
Last Week in AI
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Семь раз посчитай — один раз урони: моделируем инциденты ...
anatoly_kr · 2026-05-11 · via Все публикации подряд на Хабре

Семь раз посчитай — один раз урони: моделируем инциденты до деплоя

Уровень сложностиСредний

Время на прочтение8 мин

Охват и читатели651

Ракету не отправляют в космос только потому, что её двигатель и насос успешно прошли стендовые испытания по отдельности. Перед стартом инженеры рассчитывают траекторию, моделируют режимы работы и анализируют сценарии отказов. Расчёт не заменяет реальные тесты, но задаёт для них осмысленную рамку.

В софте всё обычно иначе. Распределённый пользовательский путь — например, оформление заказа — собирается из десятков микросервисов, баз и очередей. Разработчики добавляют новую зависимость, видят зелёные тесты, проверяют локальные метрики и выкатывают релиз. Считается, что если при сбое что-то пойдёт не так, настроенная система наблюдаемости обязательно это покажет.

Она, конечно, покажет. Но почему при проектировании микросервисов мы так спокойно относимся к тому, что узнаём о хрупкости архитектуры в основном по факту инцидента?

Эта статья о том, как получить грубый расчёт деградации системы ещё до релиза. Без отказа от хаос-инжиниринга или мониторинга, а как шаг перед ними. Я расскажу о двух экспериментах, в которых топологическая модель автоматически извлекалась из распределённых трейсов, после чего на ней просчитывались сценарии отказов методом Монте-Карло. Результаты моделирования я затем сравнивал с реальными инъекциями отказов на стендах DeathStarBench и OpenTelemetry Demo.


Почему микросервисы не моделируют

Основная проблема предварительного моделирования в IT — это цена поддержки актуальности.

Монолитную систему было относительно легко удержать в голове. С микросервисами пользовательский путь начал проходить через несколько команд и сетевых зон. Новая связь между двумя сервисами может ничего не сломать в локальных тестах, но при этом кардинально изменить картину устойчивости для всего процесса оплаты.

Поддерживать ручную модель в такой среде почти невозможно. Диаграмма в корпоративной wiki устаревает сразу после следующего коммита. Как только кто-то выносит часть логики в очередь или подключает стороннее API, схема превращается в бесполезную историческую справку. Заставлять команды рисовать актуальные схемы руками — значит просто добавить им бюрократии.

Поэтому индустрия логично сделала ставку на логи, метрики, трейсы и алерты. Это критически важные вещи, но они отвечают на вопрос о том, что сломалось сейчас, а не о том, что сломается завтра.

Если схемы рисовать долго и дорого, возникает резонный вопрос: можно ли автоматически собирать рабочую модель прямо из эксплуатационных артефактов, которые система и так производит? Распределённая трассировка, конфигурации service mesh и манифесты Kubernetes уже содержат фактическую топологию. В своих работах (и далее в статье) я буду называть процесс автоматического восстановления графа по этим данным model discovery (по-русски ближе всего «автоматическое извлечение модели»).

Суть подхода

Алгоритм выглядит довольно просто. Из распределённых трейсов восстанавливается направленный граф зависимостей. Для каждого целевого эндпоинта мы задаём условия успеха — то есть перечисляем, какие компоненты обязательно должны быть доступны для выполнения бизнес-операции. Дальше запускается Монте-Карло. В ходе симуляции часть сервисов случайным образом «выводится из строя», и для каждого сценария проверяется, остался ли жив нужный пользовательский путь. Процент успешных прогонов даёт расчётную вероятность доступности.

В псевдокоде ядро выглядит так:

for each failure_fraction:
    repeat N times:
        failed = sample_services(failure_fraction)
        alive_graph = graph - failed

        for each endpoint:
            success = reachable(entrypoint, required_targets, alive_graph)

    R_model = successful_trials / N

Я намеренно начал с предельно грубой структурной модели. Если сразу пытаться закладывать в неё штормы ретраев, размер пула соединений, таймауты и накопление очередей, инструмент усложнится настолько, что потеряет практический смысл. Задача первого слоя моделирования — проверить, даёт ли простая графовая связность полезный сигнал. Для этого результаты расчёта надо было сравнить с натурными хаос-экспериментами.

Схема пайплайна model discovery

Схема пайплайна model discovery

Кажется, что сотни тысяч графовых симуляций — это долго, но вычисления получаются дешёвыми. В моих замерах на обычных раннерах GitHub Actions (ubuntu-22.04, 4 CPU, 16 GB RAM) 500\ 000 прогонов графа занимали около 30 секунд. Причём это был исследовательский неоптимизированный код на Python с использованием networkx. То есть математика Монте-Карло не является узким местом и спокойно встраивается в обычный CI-пайплайн.

Гораздо сложнее правильно определить границы системы. В модели узлом считается любой сервис или зависимость, от которых зависит целевой путь. Всю инфраструктуру наблюдаемости (коллекторы, Jaeger) мы из зоны отказов исключаем. С базами данных и брокерами сообщений сложнее. Если трейс обрывается на клиенте (например, внутри библиотеки драйвера PostgreSQL) и база не видна как независимый узел, структурная модель по трейсам её отказ просто не заметит. Учитывать stateful-компоненты можно только тогда, когда они явно представлены в графе.

Эксперимент 1. DeathStarBench Social Network

Первый тест я проводил на академическом микросервисном бенчмарке DeathStarBench Social Network.

Из Jaeger экспортировался граф зависимостей, преобразовывался в модель, после чего рассчитывалась доступность операций. Результаты сравнивались с реальной остановкой контейнеров на стенде. Нагрузка подавалась утилитой wrk2 со стандартным профилем запросов 1:3:6.

Здесь есть важная деталь про подсчёт метрики на живом стенде. Ориентироваться только на коды HTTP 200 и 500 некорректно, потому что реальный отказ сервиса часто выражается в разрыве соединения или срабатывании таймаута. Поэтому для оценки доступности (R_{\mathrm{live}}) использовалась формула, учитывающая сетевые сбои:

R_{\mathrm{live}} = 1 - \frac{\text{HTTP 5xx} + \text{socket errors} + \text{timeouts}}{\text{total requests}}

Стенд гонялся в двух режимах — без репликации (norepl) и с ней (repl). Доля искусственно выводимых из строя узлов p_{\mathrm{fail}} варьировалась от 0.1 до 0.9. В GitHub Actions крутилась матрица из 250 запусков, каждый из которых включал симуляцию и реальные окна измерений.

Сводные результаты:

Режим

p_{\mathrm{fail}}

R_{\mathrm{model}} (расчёт)

R_{\mathrm{live}} (стенд)

norepl

0.1

0.4182 ± 0.0005

0.5533 ± 0.0031

norepl

0.3

0.1613 ± 0.0005

0.1775 ± 0.0021

norepl

0.5

0.0454 ± 0.0002

0.0376 ± 0.0006

norepl

0.7

0.0014 ± 0.0000

0.0067 ± 0.0000

norepl

0.9

0.0000 ± 0.0000

0.0000 ± 0.0000

repl

0.1

0.6281 ± 0.0005

0.6969 ± 0.0026

repl

0.3

0.3054 ± 0.0007

0.3054 ± 0.0017

repl

0.5

0.1145 ± 0.0004

0.0958 ± 0.0011

repl

0.7

0.0132 ± 0.0001

0.0155 ± 0.0003

DeathStarBench: R_model против R_live

DeathStarBench: R_model против R_live

DeathStarBench: ошибка модели по доле отказов

DeathStarBench: ошибка модели по доле отказов

На средних значениях отказов (например, repl, p_fail=0.3) прогноз совпал с реальностью до четвертого знака, а общая корреляция по точкам составила 0.992. Но куда важнее, что структурная модель корректно уловила само поведение системы. При включении репликации предсказанная доступность ожидаемо выросла.

Расхождения между моделью-стендом тоже показательны. На малых долях отказов (p_{\mathrm{fail}}=0.1) модель пессимистична. Она считает путь полностью недоступным при обрыве связи, хотя живой стенд, вероятно, вытягивает часть ситуаций за счёт внутренних механизмов восстановления (например, встроенных ретраев или резервных путей). На высоких долях отказов наблюдается обратная картина: модель слишком оптимистична, так как ничего не знает о вторичных эффектах перегруженной системы вроде переполнения пулов соединений или каскадных таймаутов.

Эксперимент 2. OpenTelemetry Demo и асинхронность

После этого я проверил подход на микросервисном приложении Astronomy Shop из OpenTelemetry Demo. Здесь граф строился уже из сырых спанов, а в топологии присутствовали асинхронные связи через Apache Kafka.

Наличие очередей заставляет чётко определиться с тем, что именно мы считаем успешным ответом. Одно дело — немедленный успех, когда пользователь получает корректный HTTP-ответ от фронтенда в рамках синхронного запроса. Совсем другое — успех отложенной обработки, когда заказ гарантированно проходит весь асинхронный пайплайн через консьюмеров.

В рамках этого теста я проверял только первый вариант (немедленный успех HTTP-запросов, например POST /api/checkout). Модель тестировалась в двух вариантах. В режиме all-blocking все зависимости, включая Kafka, считались критичными для ответа. В режиме async связи через очередь исключались из графа при оценке синхронной доступности.

Результат агрегированной симуляции на 5 \times 10^6 прогонов и натурных тестов в 5000 окон показал, что разница между этими двумя версиями модели на уровне эндпоинтов проявляется лишь в пятом знаке после запятой.

OpenTelemetry Demo: агрегированная доступность

OpenTelemetry Demo: агрегированная доступность

OpenTelemetry Demo: async минус all-block

OpenTelemetry Demo: async минус all-block

Из этого нельзя сделать вывод, что Kafka не влияет на надёжность. Вывод гораздо более узкий: для конкретного синхронного SLO потребители сообщений из очереди просто не лежат на критическом пути. Если же команда определяет успех как завершение всего флоу обработки за N секунд, асинхронные связи сразу станут центральным узлом расчёта.

Выводы и границы применимости

Оба эксперимента показали примерно одно и то же. Автоматическое извлечение графа не предсказывает сложную динамику — деградацию задержек, серые отказы, штормы ретраев и исчерпание пулов соединений.

Но свою главную задачу этот метод выполняет. Он даёт дешёвый, быстрый и автоматизированный сигнал об уязвимостях архитектуры. Инженер получает список хрупких путей, пострадавших из-за изменения связей в последних релизах. Это отличная отправная точка для прицельного хаос-инжиниринга, чтобы не ломать инфраструктуру вслепую.

Чтобы подход не превратился в набор эвристик, мы сейчас формализуем рамки применения модели. Её можно описать как M = \langle G, R, P, \Phi \rangle, где G — извлечённый граф, R — репликация, P — условия успеха, а \Phi — семантика связей.

При таком описании общую ошибку прогноза можно разложить на три компонента:

\Delta_{\mathrm{total}} \approx \Delta_{\mathrm{disc}} + \Delta_{\mathrm{sem}} + \Delta_{\mathrm{num}}

Первое слагаемое (\Delta_{\mathrm{disc}}) отвечает за алгоритм извлечения. Трейсы могли потерять часть спанов из-за сэмплирования или добавить фоновый шум. Второе слагаемое (\Delta_{\mathrm{sem}}) — это семантическая ошибка, то есть цена наших допущений вроде игнорирования таймаутов или очередей. И, наконец, \Delta_{\mathrm{num}} — это численная погрешность самого метода Монте-Карло. Такое разделение позволяет улучшать модель точечно, добавляя в неё ровно те механизмы, отсутствие которых даёт наибольшую дельту с живым стендом.

Понятно, что бенчмарки на 15–30 сервисов не гарантируют, что подход мгновенно заведётся в enterprise-ландшафте на сотни узлов. На больших объёмах главной проблемой станет не скорость симуляции, а качество исходных данных: рваные трейсы, неучтённые базы и сложные механизмы резервирования.

Если кто-то готов проверить эту механику на своей инфраструктуре, я буду рад совместному эксперименту. Доступы к проду или развёртывание сторонних агентов не требуются. Достаточно выгрузить обезличенные трейсы за определённый период и сопоставить их с историей реальных деградаций за то же время. Мы сможем проанализировать данные и проверить, подсветила бы графовая модель те узлы, которые в итоге стали причиной инцидентов. Если интересно — пишите в личку, в комменты, whatever else.

Артефакты, код и ссылки

Описанный пайплайн сейчас собирается в набор open-source инструментов MB3R Lab. Утилита Bering отвечает за извлечение топологии, а Sheaft производит симуляции и оценку устойчивости (обе написаны на Go).

Все результаты, исходный код тестов и бенчмарков лежат на GitHub:

Академическое обоснование этих экспериментов можно найти в профильных работах:

  1. Model Discovery and Graph Simulation: A Lightweight Gateway to Chaos Engineering, ICSE-NIER 2026 (работа получила Distinguished Paper Award).

  2. Refining Resilience Model Discovery: A Case Study on the Limited Role of Asynchronous Edges in the OpenTelemetry Demo, AINA 2026 (если статья ещё не вышла, вот препринт на arXiv).

Можем ли мы построить мир, где не будет ночных дежурств? Распределённые системы стали слишком сложными, чтобы предсказывать их поведение по метрикам отдельных сервисов. Пользовательский путь живёт на графе зависимостей, и перед деплоем есть смысл заранее просчитывать, как этот граф переживёт отказ узлов. Извлечение модели по трейсам — это попытка сделать такой расчёт без рутинного рисования схем.

Дополнительные заметки по формальным методам, системной инженерии, моделированию и всякому другому я публикую в канале MB3R Lab.