Workflow: проектирование системы от начала до конца#
Двенадцать шагов от «пришла задача» до «дизайн принят». Порядок не ритуальный: каждый шаг производит артефакт, который нужен следующему. Пропуск шага не экономит время — он переносит стоимость ошибки в код.
Документ описывает процесс. Механики (что такое шардирование, как работает Kafka) лежат в карточках topics/, ссылки стоят на каждом шаге.
flowchart TD
W0[W0 · Требования] --> W1[W1 · Оценки]
W1 --> W2[W2 · Контракты]
W2 --> W3[W3 · Данные]
W3 --> W4[W4 · Архитектура]
W4 --> W5[W5 · Масштабирование]
W5 --> W6[W6 · Согласованность]
W6 --> W7[W7 · Надёжность]
W7 --> W8[W8 · Безопасность]
W8 --> W9[W9 · Эксплуатация]
W9 --> W10[W10 · Стоимость и trade-offs]
W10 --> W11[W11 · Design review + ADR]
W5 -.пересчёт.-> W1
W6 -.меняет модель.-> W3
W11 -.новые требования.-> W0
Итеративность. Первый проход делается быстро и грубо: W0→W4 за один присест, потом W5→W7 показывают, что оценки или модель данных не сходятся, и вы возвращаетесь. Нормальный дизайн — два-три круга, а не один идеальный проход.
Быстрый проход (интервью, 45 минут). W0 (5 мин) → W1 (5) → W2 (5) → W3 (10) → W4 (10) → W5/W6 точечно по узким местам (10). W7–W11 — только упоминанием, если спросят.
Стадия системы и шаги. Шаги и их порядок одинаковы на всех стадиях — ни один из четырёх прогонов не исключил ни одного шага. Различается наполнение. Блок «по стадиям» стоит только там, где стадия меняет то, что шаг делает, — на пяти шагах из двенадцати: W0, W1, W3, W4, W9. У остальных семи стоит строка «на всех стадиях одинаково», и это не заглушка: пустой блок «здесь ничего особенного» — приглашение заполнить его чем-нибудь.
Граница проведена так: если стадия меняет как читается правило внутри документа, это дело документа — его поля «Стадия» и правил мастер-шаблона, — а не блока в шаге. Два ближайших промаха названы, чтобы граница была видна. На W2 знание о потребителях на гринфилде закладывается, а не покупается; на W5 узкое место нечем подтвердить замером. Оба меняют чтение D-11 и D-03, но не меняют работу шага.
«Под изменением» отдельной колонки не имеет — это режим работающей системы, и всё сказанное про неё действует и там. Своё появляется только у W3, где шаг раздваивается, и у W9.
W0 · Рамки и требования#
Документы шага: D-10 гринфилд · работающая
По стадиям.
| Стадия | Что меняется на этом шаге |
|---|---|
| гринфилд | Требований не у кого спросить наблюдением: поведения нет. Инварианты и цели назначаются и становятся фактом потому, что так записали. Обещание и измеритель расходятся во времени: сначала строится измеритель, потом даётся обещание, а до первого трафика цель остаётся прогнозом |
| работающая | Половина требований читается из поведения: что уже обещано по умолчанию, что ломается, на что жалуются. Измеритель чаще всего есть, и вопрос в том, с чьей он точки зрения |
Различие частичное: набор вопросов шага один и тот же, расходится источник ответов — и вместе с ним пометка в ячейке.
Цель. Понять, что строим и по каким числам поймём, что оно работает.
Вход. Запрос заказчика, идея, задача с интервью. Выход. Одна страница: сценарии, функциональные требования, нефункциональные требования с числами, ограничения, допущения, явный список «вне рамок».
Числа в нефункциональных требованиях — это обещание, и у него должен быть измеритель. Какую цель ставить, чем её мерить и сколько стоит измерение — D-10 · Цели уровня обслуживания и их измерение. Правило оттуда простое: обещать можно только то, что уже измеряется; всё остальное — план построить измеритель, а не цель.
Вопросы, на которые надо ответить.
- Кто пользователи, сколько их сейчас и через год?
- Какие 3–5 сценариев критичны? Остальные — вторичны по определению.
- Что дороже: недоступность или рассогласованность данных? (Ответ определит половину дальнейших решений.)
- Какой бюджет задержки у ключевого сценария — для пользователя, а не для сервера?
- Какая доля чтений к записям? Какой профиль нагрузки — ровный, пиковый, сезонный?
- Что с данными: сколько хранить, можно ли удалять, есть ли требования регуляторов?
- Какие внешние системы обязательны и какие у них ограничения?
- Что явно не делаем в этой версии?
Формулировка NFR (non-functional requirements, нефункциональных требований). «Быстро и надёжно» — это не требование. Требование выглядит так:
Доступность API 99.9 % в месяц (≈ 43 мин простоя). p99 ответа на чтение ленты ≤ 300 мс при 5 000 RPS. Потеря подтверждённой записи недопустима (RPO = 0), восстановление после отказа региона ≤ 30 мин (RTO).
Типовые ошибки. Начать с рисования компонентов, не поговорив о требованиях. NFR без чисел. Не зафиксировать «вне рамок» — тогда объём растёт молча.
Готово, когда. Каждое NFR имеет число и способ измерения; требования приоритезированы; есть список исключений.
Связано: OPS-09 SLI, SLO и бюджет ошибок · SEC-11 threat modeling · DATA-19 retention и приватность · PERF-11 стоимость как требование · ARCH-11 офлайн и ненадёжная сеть · Источники: Google SRE Book, гл. 4 «Service Level Objectives», AWS Well-Architected Framework.
W1 · Оценки на салфетке#
Документы шага: нет — шаг идёт по карточкам.
По стадиям.
| Стадия | Что меняется на этом шаге |
|---|---|
| гринфилд | Все числа — предсказания, и работа не в самих числах, а в проверке на порядок: что изменится, если ошиблись в десять раз. Ошибка на порядок меняет архитектуру, ошибка в полтора раза — нет |
| работающая | Числа берутся из того, что уже меряется, и работа — найти их, а не вывести. Своя ловушка: меряется обычно не то, что нужно шагу |
Ловушка общая для обеих стадий, но найдена на гринфилде: шаг считает входные события, а не то, во что событие разворачивается. На прогоне U-02 0,17 подачи в секунду обернулись 933 обращениями к справочникам — событие развернулось в 5 500 раз.
Цель. Понять порядок величин: нужна ли вообще распределённая система, или задача решается одной БД и кэшем.
Выход. Табличка чисел:
- DAU (активные пользователи за сутки);
- RPS (запросы в секунду) — средний и пиковый;
- размер записи;
- объём данных за год;
- исходящий трафик;
- бюджет задержки по компонентам.
Метод. Сверху вниз, в порядках величин, с явными допущениями:
- Пользователи → действия на пользователя в день → средний RPS = действия / 86 400.
- Пиковый RPS = средний × коэффициент пика (обычно 3–10, для событийных систем — до 100).
- Объём = записей в сутки × размер записи × срок хранения × коэффициент репликации/индексов (×2–3).
- Трафик = RPS × размер ответа. Часто в деньги упирается он, а не CPU.
- Бюджет задержки: разложить целевой p99 по участкам (сеть, API gateway, сервис, БД, сериализация) и проверить, что сумма меньше цели.
Пункты 1–4 считает калькулятор. Он стоит ниже на сайте памятки и в репозитории не работает: GitHub не выполняет скрипты. Кроме самих чисел он показывает то, чего требует стадия гринфилда: меняется ли вывод, если ошиблись в десять раз. А если оставить разворачивание единицей, калькулятор напомнит о нём. Формулы живут здесь, в шаге: разойдётся с ними калькулятор — прав шаг.
Ориентиры для проверки правдоподобия.
- один узел PostgreSQL уверенно держит тысячи простых транзакций в секунду;
- один узел Redis — сотни тысяч операций;
- сеть внутри ЦОД ≈ 0.5 мс, между регионами — десятки миллисекунд;
- чтение с SSD ≈ 100 мкс, с жёсткого диска ≈ 10 мс.
Типовые ошибки.
- считать по среднему и не заложить пик;
- забыть про трафик и его стоимость;
- считать с точностью до процента там, где неизвестен порядок;
- не пересчитать после W5.
Готово, когда. Видно узкое место: что упрётся первым — CPU, диск, сеть или деньги.
Связано: PERF-01 числа задержек · PERF-02 перцентили и хвост · PERF-07 закон Литтла и насыщение · OPS-11 ёмкость и автомасштабирование · PERF-08 нагрузочное тестирование · PERF-11 unit-экономика · Источники: Latency Numbers Every Programmer Should Know, Gil Tene, How NOT to Measure Latency.
W2 · Контракты и API#
Документы шага: D-11 гринфилд · работающая
По стадиям. На всех стадиях одинаково.
Цель. Зафиксировать границу между частями системы раньше, чем появится реализация.
Выход. Список операций с сигнатурами, выбранный стиль API, схема данных, модель ошибок, правила идемпотентности, пагинации и версионирования.
Решения этого шага.
- Синхронно или асинхронно. Если операция может занять больше сотен миллисекунд или зависит от третьей стороны — она асинхронная, и в контракте появляется статус операции.
- Стиль. REST для ресурсных CRUD-подобных API, gRPC для внутренних вызовов с жёсткими контрактами и стримингом, GraphQL — когда клиентов много и им нужны разные срезы.
- Push или pull. Нужен ли сервер-инициированный поток: polling, long polling, SSE (server-sent events), WebSocket.
- Идемпотентность. Любая небезопасная операция, которую клиент может повторить (а он повторит — по таймауту), нуждается в ключе идемпотентности.
- Ошибки. Различать «повторяй» и «не повторяй»: это контракт для повторов клиента.
- Совместимость. Как выкатывать клиент и сервер независимо.
Совместимость — это обещание, и у него есть адресат. Как версионировать, описано в NET-17; что мы обещаем и кому — D-11 · Обещание совместимости интерфейса. Обещание там определено как нижняя граница предупреждения, у неё три уровня: «не сузим никогда», «не сузим раньше объявленного срока», «без гарантий». Выбирается оно не вкусом, а тем, что мы знаем о потребителях. Правило оттуда: срок, объявленный тем, кого мы не видим, для потребителя неотличим от отсутствия срока, и записывать его надо честно.
Типовые ошибки.
- проектировать API от таблиц БД;
- возвращать 200 с ошибкой в теле;
- пагинировать по offset растущую коллекцию;
- оставить без идемпотентности платёжные и «создающие» операции;
- написать политику совместимости раньше, чем появился список тех, кому её объявлять.
Готово, когда. По контракту можно написать и клиент, и заглушку сервера, не задавая вопросов.
Связано: NET-08 стили API · MSG-01 модели взаимодействия · NET-12 realtime-транспорт · NET-13 асинхронные операции · NET-16 идемпотентность · NET-17 версионирование · NET-18 контракты и схемы · весь блок B01 · Сеть, протоколы, API · Источники: Stripe API — Idempotent Requests, Google API Design Guide, RFC 9110 — HTTP Semantics.
W3 · Данные: модель и хранилище#
Документы шага: D-01 гринфилд · работающая · D-07 гринфилд · работающая · D-08 под изменением
По стадиям.
| Стадия | Что меняется на этом шаге |
|---|---|
| гринфилд | Копий данных нет ни одной, и вопрос «сколько их уже есть» читается как «сколько мы заведём»: ответ — решение, а не замер. D-08 неприменим: переезжать не от чего. Первичная загрузка справочников — ввод, а не переезд |
| работающая | Копии существуют и считаются. Появляется вторая половина вопроса — как перейти, — и её легко принять за исполнение первой |
| под изменением | Шаг раздваивается: «какой системе быть» (D-07) и «как в неё перейти» (D-08) — разные решения с разными дисквалификаторами и общим окном с D-09. Второе легко не заметить: оно выглядит исполнением первого, а по данным изменение системы ломает её чаще, чем её собственный код |
Цель. Выбрать модель и хранилище от того, как данные читают и пишут, а не от привычки.
Выход. Концептуальная модель, список паттернов доступа, выбор хранилищ с обоснованием, ключи и стратегия роста.
Порядок действий.
- Выписать сущности и связи.
- Выписать паттерны доступа: «получить ленту пользователя за период, 5 000 RPS, p99 200 мс», «найти заказ по номеру», «отчёт за месяц».
- Для каждого паттерна — какой индекс или ключ его обслуживает.
- Выбрать хранилище: реляционное по умолчанию; отклонение от умолчания требует обоснования (объём, форма данных, профиль нагрузки).
- Решить, что будет источником истины, а что — производной проекцией (кэш, поисковый индекс, витрина).
Ключевые развилки. Нормализация против денормализации (стоимость чтения против стоимости согласованности). Один тип хранилища или несколько (polyglot persistence — это ещё и несколько операционных контуров). Разделение OLTP и OLAP (транзакционной и аналитической нагрузки).
Типовые ошибки.
- выбор БД до формулировки паттернов доступа;
- аналитика на БД прода;
- ключ шардирования, выбранный до того, как понятен профиль запросов;
- хранение файлов в БД.
Готово, когда. Для каждого критичного запроса понятно, какой индекс его закрывает и сколько данных он трогает.
Решения этого шага. D-01 · Выбор хранилища — вопросы, оси, дисквалификаторы, рыночный слой. Шаг говорит, что решить; документ решения — как выбрать и что приложить к ADR (architecture decision record, запись архитектурного решения).
Связано: DATA-01 выбор хранилища · DATA-03 моделирование от паттернов доступа · DATA-05 индексы · DATA-04 типы данных: деньги и время · DATA-02 специализированные хранилища · DATA-15 OLTP и OLAP · DIST-09 генерация уникальных ID · весь блок B03 · Хранилища и данные · Источники: Kleppmann, «Designing Data-Intensive Applications», гл. 2–3, Amazon DynamoDB — Best Practices for Design.
W4 · Верхнеуровневая архитектура#
Документы шага: D-05 гринфилд · D-02 работающая
По стадиям.
| Стадия | Что меняется на этом шаге |
|---|---|
| гринфилд | Границы закладывают предсказанием: истории изменений нет, измерять связность нечем. Документ шага — D-05. Дешёвое здесь то, что после запуска дорого: стянуть класс защищаемых данных в одну границу ничего не стоит |
| работающая | Границы режут по измерению — связность изменений считается по репозиторию и трекеру. Документ шага — D-02 |
Единственный шаг, где стадия меняет сам документ, а не его прочтение. Взять не тот — не неточность, а неприменимый метод: раздел 1 D-02 на гринфилде заполнять нечем.
Цель. Собрать компоненты и показать, как проходит запрос.
Выход. Диаграмма компонентов (C4 уровня «контейнеры») + пошаговый проход 2–3 ключевых сценариев: кто кого вызывает, что пишется, что читается.
Правила.
- Компонент появляется в схеме, только если у него есть зона ответственности одной фразой. «Сервис обработки» — не зона ответственности.
- Показать поток данных, а не только стрелки: что передаётся и в каком объёме.
- Отметить синхронные и асинхронные границы разными линиями — это будущие точки отказа.
- Сразу отметить, где данные дублируются (кэш, индекс, проекция) — это будущие точки рассогласования.
Типовые ошибки. Схема из 15 квадратов без потоков. Микросервисы «на будущее» при одной команде и 100 RPS. Отсутствие ответа на вопрос «что произойдёт, если этот квадрат недоступен».
Готово, когда. По схеме можно проследить путь ключевого запроса и назвать хранилище истины для каждой сущности.
Решения этого шага. Два, по стадии проекта: метод у них разный, а не только числа. Какой когда — сказано в блоке «по стадиям» в начале шага.
Связано: NET-21 устройство веб-приложения · DIST-11 карта паттернов · ARCH-01 монолит и микросервисы · ARCH-02 границы контекстов · ARCH-03 внутренняя архитектура сервиса · ARCH-04 хореография и оркестрация · MSG-02 очередь против лога · EDGE-03 API gateway · весь блок B07 · Архитектурные стили · Источники: C4 model, arc42.
W5 · План масштабирования#
Документы шага: D-03 гринфилд · работающая
По стадиям. На всех стадиях одинаково.
Цель. Понять, что делать, когда нагрузка вырастет в 10 и в 100 раз — и не делать этого заранее.
Порядок применения. Шаги идут строго по очереди:
- Измерить — найти реальное узкое место, а не предполагаемое.
- Вертикально — увеличить машину. Скучно, но до определённого масштаба дешевле всего.
- Кэш — снять чтения, если нагрузка в основном на чтение.
- Реплики чтения — если кэш не спасает; сразу принять лаг репликации как факт.
- Асинхронность — вынести всё, что не нужно клиенту немедленно, в очередь.
- Шардирование — когда один узел не держит записи или объём.
- Разделение сервисов — когда причина не в нагрузке, а в организации и цикле релизов.
Типовые ошибки.
- начать с шардирования;
- кэшировать то, что не узкое место;
- считать горизонтальное масштабирование бесплатным: оно переносит стоимость в согласованность и эксплуатацию;
- не пересчитать оценки W1 после изменений.
Готово, когда. Для каждого узкого места есть следующий шаг и известен признак, по которому его пора делать.
Решения этого шага. D-03 · Стратегия кэширования — короткая форма: умолчание и условия отклонения вместо сравнения вариантов, потому что решение обратимо, а ошибка стоит дней.
Связано: DIST-01 вертикально против горизонтально · CACHE-01 уровни кэша · DATA-09 репликация · DATA-10 шардирование · EDGE-01 балансировка нагрузки · PERF-06 пулы соединений и N+1 · PERF-05 оптимизация API
W6 · Согласованность и корректность#
Документы шага: D-04 гринфилд · работающая
По стадиям. На всех стадиях одинаково.
Цель. Определить, где нужна строгая согласованность, а где допустима отложенная — и как это не сломается при повторах и гонках.
Что решается.
- Границы транзакций. Что должно меняться атомарно. Всё, что не поместилось в одну транзакцию, становится распределённой операцией.
- Модель согласованности для каждого чтения: строгая, read-your-writes, causal (причинная), eventual (отложенная). У разных экранов разные требования.
- Распределённые операции.
- saga (оркестрация или хореография) с компенсациями;
- transactional outbox для атомарной записи «в БД + в очередь»;
- 2PC (two-phase commit, двухфазная фиксация) — только когда участники её поддерживают и вы готовы к блокировкам.
- Идемпотентность и дедупликация. Повтор должен быть безопасным на всех уровнях: клиент → API → потребитель.
- Гонки за дефицитным ресурсом (билет, остаток на складе, уникальный ник): оптимистическая блокировка с версией, уникальный индекс, резервирование с TTL.
Типовые ошибки. Считать, что «есть транзакции» = «нет гонок» (read committed допускает write skew — перекос записи). Двойная запись в БД и очередь без outbox. Обещание exactly-once (ровно один раз) там, где его обеспечивает только дедупликация по ключу.
Готово, когда. Для каждой критичной операции описано поведение при повторе, частичном отказе и параллельном выполнении.
Решения этого шага. D-04 · Связь сервисов в рабочем процессе — три двоичных вопроса задают ячейку из восьми; принимается для каждого процесса, пересекающего границы сервисов, отдельно.
Связано: DATA-07 ACID и транзакции · DATA-08 уровни изоляции · DIST-03 модели согласованности · DIST-08 распределённые транзакции и saga · MSG-07 transactional outbox · MSG-06 гарантии доставки · NET-16 идемпотентность · весь блок B06 · Распределённые системы · Источники: Kleppmann, DDIA, гл. 7 и 9, microservices.io — Saga, PostgreSQL — Transaction Isolation.
W7 · Надёжность и деградация#
Документы шага: D-06 гринфилд · работающая
По стадиям. На всех стадиях одинаково.
Цель. Описать поведение системы при отказах — потому что отказ не гипотеза, а расписание.
Инструмент — матрица отказов. Для каждого компонента: что откажет → что увидит пользователь → что делает система → как узнаем.
| Отказ | Последствие | Реакция | Обнаружение |
|---|---|---|---|
| Реплика БД недоступна | Рост задержки чтений | Переключение на другую реплику, чтение с лидера для критичных запросов | Алерт по ошибкам пула |
| Payment gateway (платёжный шлюз) тормозит | Очередь запросов, исчерпание пула | Таймаут 2 с, circuit breaker, очередь на повтор | p99 внешнего вызова |
| Пропала половина подов | Просадка ёмкости | Автоскейлинг, ограничение нагрузки | Readiness-проба, SLO |
Что отключаем и что показываем вместо — решение, а не механика. Механизмы ниже описаны в карточках блока REL и обычно известны команде. Неизвестно другое: что система обещает показать, когда правильный ответ недоступен. Это D-06 · Деградация при отказе и перегрузке, и принимается оно по функции, а не по системе.
Обязательные механики.
- таймауты на каждом сетевом вызове, без исключений;
- повторы с exponential backoff и jitter, ограниченные бюджетом;
- circuit breaker перед нестабильными зависимостями;
- bulkhead — изоляция пулов, чтобы одна зависимость не съела все потоки;
- graceful degradation (плавная деградация): что отключаем первым (рекомендации, персонализация) и что защищаем до последнего (оформление заказа).
Уровень выше. Multi-AZ (несколько зон доступности) по умолчанию; multi-region — только если этого требует SLO, потому что цена высокая. Бэкапы, проверенные восстановлением, RPO и RTO как числа.
Типовые ошибки. Повторы без jitter и без бюджета (усиливают сбой). Отсутствие таймаута по умолчанию. Health check, проверяющий процесс, но не зависимости — или наоборот, роняющий живые узлы из-за чужой проблемы.
Готово, когда. Матрица отказов заполнена, у каждой строки есть реакция и способ обнаружения; известны RPO/RTO.
Связано: REL-06 обзор отказоустойчивости · REL-01 таймауты и повторы · REL-02 circuit breaker и bulkhead · REL-03 load shedding · REL-04 деградация и фича-флаги · REL-07 ячеистая архитектура · REL-09 бэкапы, RPO и RTO · DIST-06 обнаружение отказов · весь блок B08 · Надёжность · Источники: Nygard, «Release It!», AWS Builders' Library — Timeouts, retries and backoff with jitter.
W8 · Безопасность#
Документы шага: нет — шаг идёт по карточкам.
По стадиям. На всех стадиях одинаково.
Цель. Закрыть аутентификацию, авторизацию, данные и периметр — до того, как система появится в интернете.
Что описывается.
- Аутентификация. Сессии или токены; для сторонних клиентов — OAuth 2.0 / OIDC (OpenID Connect). Хранение паролей — только сильный медленный хэш с солью.
- Авторизация. Модель прав (RBAC / ABAC / ReBAC) и место проверки: в API gateway, в сервисе или в запросе к данным. Проверка «на клиенте» — не проверка.
- Данные. Что считается персональными данными, что шифруется в покое и в канале, где ключи, как ротируются, что попадает в логи (и что не должно).
- Периметр. Rate limiting, ограничение размера запроса, валидация ввода, CORS, защита от перебора.
- Секреты. Хранилище секретов, ротация, отсутствие секретов в репозитории и в переменных окружения образа контейнера.
- Аудит. Кто, что и когда сделал с чувствительными данными.
Мини-threat model (моделирование угроз). Для каждого входа в систему: кто может обратиться, что подделает, что перехватит, чем перегрузит.
Типовые ошибки.
- авторизация «по факту наличия токена»;
- секреты в конфигах;
- PII (персональные данные) в логах и трассировках;
- rate limiting только на уровне пользователя, но не на уровне IP или ключа.
Готово, когда. Для каждой роли и каждого ресурса ясно, кто имеет доступ и где это проверяется.
Связано: SEC-01 аутентификация · SEC-04 авторизация · SEC-06 безопасность API · SEC-07 типовые атаки · SEC-08 шифрование и секреты · SEC-09 транспортная безопасность · EDGE-06 rate limiting · SEC-11 threat modeling · весь блок B09 · Безопасность · Источники: OWASP API Security Top 10, RFC 9700 — OAuth 2.0 Security Best Current Practice, NIST SP 800-207 — Zero Trust.
W9 · Observability и эксплуатация#
Документы шага: D-09 гринфилд · работающая
По стадиям.
| Стадия | Что меняется на этом шаге |
|---|---|
| гринфилд | Наблюдать нечего: трафика нет и не будет до запуска. Шаг превращается из «что мы видим» в «что построить к первому дню», и его результат — список сигналов с ценой, а не отчёт о текущем состоянии. У первой выкатки нет предыдущей версии, и часть вопросов об откате на нём не срабатывает |
| работающая | Сигналы есть; работа — проверить, отвечают ли они на вопрос последнего разбора, и во что обходятся при десятикратном росте |
| под изменением | Добавляется то, чего нет в обоих остальных: две версии работают одновременно, и observability должна различать их. Окно сосуществования — общее с W3 и с D-08 |
Цель. Сделать систему диагностируемой и выпускаемой.
Observability (наблюдаемость).
- Метрики. Для сервисов — RED (Rate, Errors, Duration), для ресурсов — USE (Utilization, Saturation, Errors). Следить за перцентилями, не за средним.
- Логи. Структурированные, с идентификатором запроса, без чувствительных данных.
- Трассировка. Сквозной trace ID через все сервисы и очереди — иначе распределённый запрос не разобрать.
- SLI/SLO и бюджет ошибок (error budget). Алерты по симптомам, видимым пользователю, а не по загрузке CPU.
Эксплуатация.
- стратегия выкатки: rolling, blue-green, canary;
- фича-флаги;
- план миграций схемы без простоя: expand → migrate → contract;
- runbook (инструкция дежурному) на каждый алерт;
- постмортемы без поиска виноватых.
Стратегия выкатки выбирается однажды, обратимость — на каждое изменение. D-09 · Обратимость выката отвечает на вопрос, который стратегия не задаёт. Сможет ли предыдущая версия работать с состоянием мира после выкатки — со схемой, с сообщениями, уже лежащими в очередях, с кэшами и контрактами? «Откат за секунды» из описания стратегии бывает фикцией, и обнаруживается это в единственный неподходящий момент.
Типовые ошибки.
- алерт на каждую аномалию — дежурный перестаёт их читать;
- логи без trace ID;
- метрики с высокой кардинальностью, роняющие систему мониторинга;
- миграция схемы, требующая одновременной выкатки кода.
Готово, когда. На вопрос «пользователю плохо — в каком месте?» отвечает дашборд, а не догадка.
Связано: OPS-07 observability · OPS-09 SLI, SLO, бюджет ошибок · OPS-10 алертинг и дежурства · OPS-02 стратегии выкатки · DATA-17 миграции без простоя · OPS-12 тестирование · OPS-03 окружения и тестовые данные · OPS-13 отладка в проде · весь блок B10 · Доставка и эксплуатация · Источники: Google SRE Book, OpenTelemetry docs, Brendan Gregg — USE Method.
W10 · Стоимость и trade-offs#
Документы шага: нет — шаг идёт по карточкам.
По стадиям. На всех стадиях одинаково.
Цель. Показать, что вариант выбран осознанно, а не потому, что первым пришёл в голову.
Выход. Сравнение 2–3 альтернатив по осям: сложность, задержка, согласованность, стоимость, операционная нагрузка, обратимость решения.
| Ось | Вопрос |
|---|---|
| Сложность | Сколько новых компонентов надо эксплуатировать? |
| Задержка | Что происходит с p99 ключевого сценария? |
| Согласованность | Что пользователь увидит устаревшим и надолго ли? |
| Стоимость | Сколько стоит запрос и сколько — хранение за год? |
| Операции | Кто дежурит и что чинит в 3 часа ночи? |
| Обратимость | Насколько дорого откатить это решение через полгода? |
Правило. Необратимые решения (формат хранения, ключ шардирования, публичный контракт) требуют больше анализа, чем обратимые (алгоритм балансировки, размер пула). Обратимые решения принимаются быстро и правятся по данным.
Типовые ошибки. Сравнение только по производительности. Игнорирование операционной стоимости нового компонента. Отсутствие оценки «сколько это будет стоить в деньгах».
Связано: PERF-11 стоимость и TCO · OPS-08 стоимость observability · ARCH-09 serverless: когда выгоден · OPS-05 Kubernetes: чего стоит · ARCH-01 монолит против микросервисов · CASE-13 разборы реальных архитектур · Источники: AWS Well-Architected — Cost Optimization Pillar, ByteByteGo — System Design Was HARD - Until You Knew the Trade-Offs, ByteByteGo — System Design Was HARD - Until You Knew the Trade-Offs, Part 2.
W11 · Design review и ADR#
Документы шага: нет — шаг идёт по карточкам.
По стадиям. На всех стадиях одинаково.
Цель. Проверить дизайн чужими глазами и записать, почему решили так.
Чек-лист ревью#
Требования
- NFR выражены числами и измеримы
- Явно записано, что вне рамок
- Профиль нагрузки: пик, а не среднее
Данные
- Для каждого критичного запроса известен обслуживающий индекс
- Определён источник истины для каждой сущности
- План роста: что делаем при ×10 и ×100
- Миграции схемы возможны без простоя
Корректность
- Границы транзакций явные
- Все небезопасные операции идемпотентны
- Распределённые операции имеют компенсации
- Гонки за дефицитным ресурсом разобраны
Отказы
- Таймаут на каждом внешнем вызове
- Повторы с jitter и бюджетом
- Заполнена матрица отказов
- Известны RPO и RTO, бэкап проверен восстановлением
Эксплуатация
- SLI/SLO определены, алерты по симптомам
- Сквозная трассировка
- Стратегия выкатки и отката
Безопасность
- Модель авторизации и место проверки
- Секреты вне кода, PII вне логов
- Rate limiting на периметре
Стоимость
- Оценена стоимость запроса и хранения
- Сравнены альтернативы, компромисс записан
Запись решений#
Форма ADR (architecture decision record) — одна на весь документ и версионируется: decisions/01-adr-template.md. Копия формы здесь была бы вторым источником правды и разошлась бы с первым на первой же правке — ровно та ошибка, от которой ADR и защищает.
Каждый ADR в поле «Метод» указывает документ решения с версией и, если он есть, дату рыночного снимка: decisions/02-versioning.md. Через год это единственный способ понять, что в старом решении нужно перепроверить, а что можно не трогать.
Принятый ADR не редактируется. Пересмотр — новый ADR, отменяющий старый; в старом дописывается только строка статуса и ссылка вперёд.
Решения, принятые по пути, собраны в decisions/: к моменту W11 их обычно три-пять, и ADR пишутся по ним, а не с чистого листа.
Связано: REL-06 обзор отказоустойчивости · DATA-16 целостность и сверка данных · SEC-11 threat modeling · OPS-09 SLO и бюджет ошибок · PERF-11 стоимость · антипаттерны как второй чек-лист · числа и матрицы выбора
Источники: Michael Nygard — Documenting Architecture Decisions, ByteByteGo — System Design Interview – BIGGEST Mistakes to Avoid.