Перейти к содержанию

B10 · Доставка и эксплуатация#

Как система попадает в прод и как там живёт. Дизайн, который нельзя выкатить без простоя и в котором нельзя разобраться во время инцидента, не завершён. Эксплуатационные свойства проектируются вместе с остальными, а не добавляются потом.

Блок — про свойства эксплуатации: observability (наблюдаемость), целевые уровни, ёмкость, стоимость, — а не про инструменты вроде Docker, Kubernetes, Git и Linux. Поэтому карточки о ролях, репозиториях и релизе мобильных приложений (OPS-14…OPS-16) сознательно сделаны короткими справками. Иначе инструменты и практики заняли бы в блоке больше места, чем свойства.

Навигация: OPS-01 · OPS-02 · OPS-03 · OPS-04 · OPS-05 · OPS-06 · OPS-07 · OPS-08 · OPS-09 · OPS-10 · OPS-11 · OPS-12 · OPS-13 · OPS-14 · OPS-15 · OPS-16 · OPS-17


OPS-01 · CI/CD#

Шаг W9

TL;DR. CI (continuous integration, непрерывная интеграция) — про то, чтобы изменения сливались часто и проверялись автоматически. CD (continuous delivery, непрерывная доставка) — про то, чтобы любая проверенная сборка могла уехать в прод в любой момент.

Проблема. Чем реже выкатка, тем больше изменений в ней и тем труднее понять, что сломалось. Редкие выкатки становятся событиями, к которым готовятся, откладывают на «после релиза» и проводят ночью. Это порочный круг: страх увеличивает размер поставки, размер увеличивает риск, риск усиливает страх.

Как работает.

  • Непрерывная интеграция. Ветки живут часы, а не недели; каждый коммит собирается и прогоняет тесты; сломанная сборка чинится немедленно и имеет приоритет над новой работой.
  • Одна сборка на все окружения. Артефакт собирается один раз и продвигается по окружениям неизменным; различия — только в конфигурации (OPS-06). Пересборка для прода означает, что тестировали не то, что выкатили.
  • Конвейер как код — в репозитории, ревьюится, версионируется вместе с приложением.
  • Быстрая обратная связь. Быстрые проверки первыми: сборка и модульные тесты в минутах, длинные — параллельно и позже. Конвейер длиннее пятнадцати минут перестают ждать, и его начинают обходить.
  • Продвижение через quality gates (качественные ворота), а не через ручные согласования: набор проверок определяет, идёт ли сборка дальше.
  • Автоматический откат (OPS-02) — часть конвейера, а не отдельная героическая процедура.

Continuous delivery против continuous deployment. Delivery — готовность выкатить в любой момент, решение принимает человек. Deployment — выкатка происходит автоматически после прохождения проверок. Второе требует зрелых тестов, фича-флагов (REL-04) и хорошей observability (наблюдаемости); переходить к нему стоит, когда первое уже работает.

Trade-offs и режимы отказа. Нестабильные тесты (flaky tests) — главный убийца доверия к конвейеру. После нескольких ложных падений красную сборку начинают перезапускать не глядя, и конвейер перестаёт что-либо гарантировать. Долгий конвейер вынуждает объединять изменения, возвращая проблему больших поставок. У конвейера доступ к секретам и проду, поэтому он сам — объект защиты (SEC-10).

Что мерить.

  • четыре показателя доставки (метрики DORA — DevOps Research and Assessment): частоту выкаток, время от коммита до прода, долю выкаток с отказом, время восстановления;
  • длительность конвейера;
  • долю нестабильных тестов.

Связано: OPS-02 стратегии выкатки · OPS-03 окружения · OPS-12 тестирование · SEC-10 цепочка поставок · OPS-14 роли DevOps и SRE · OPS-15 монорепозиторий

Источники: Martin Fowler — Continuous Integration · Accelerate / DORA metrics · Jez Humble — Continuous Delivery · ByteByteGo — CI/CD In 5 Minutes | Is It Worth The Hassle: Crash Course System Design #2 · ByteByteGo — How Big Tech Ships Code to Production


OPS-02 · Стратегии выкатки#

Шаг W9

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

Проблема. Одновременная замена всех экземпляров — это окно недоступности и мгновенное распространение возможной ошибки на всех. Нужен способ обновляться постепенно, наблюдать за поведением новой версии и уметь откатиться до того, как проблему заметят.

Стратегии

Стратегия Как работает Плюс Минус
Rolling Экземпляры заменяются порциями Не нужен двойной запас ресурсов Обе версии работают одновременно; откат медленный
Blue-green Поднимается полная вторая среда, трафик переключается разом Мгновенный откат Двойные ресурсы; общая БД остаётся общей
Canary Малая доля трафика на новую версию, наблюдение, постепенное расширение Раннее обнаружение на реальном трафике Нужны метрики сравнения и автоматика
Dark launch (тёмный запуск) Новый код исполняется, результат не показывается Проверка без риска Двойная нагрузка; только для чтения
Фича-флаг Код выкатан, поведение включается отдельно Выкатка отделена от релиза; мгновенное отключение Флаги копятся (REL-04)

Что делает выкатку безопасной независимо от стратегии.

  • Обратная совместимость на время сосуществования. Во время выкатки работают обе версии, и они делят БД, очереди и кэш. Отсюда правило expand/contract: сначала выкатывается изменение, совместимое со старой версией, потом — использующее его (DATA-17, NET-17).
  • Корректное завершение (graceful shutdown) — экземпляр перестаёт принимать новые запросы, дозавершает текущие и только потом останавливается (REL-05).
  • Критерии отката, заданные заранее в виде чисел: рост ошибок или задержки против базовой линии. Решение об откате не должно приниматься спором в чате.
  • Откат должен быть проверен. Возможность вернуться, которой ни разу не пользовались, — предположение.

Trade-offs и режимы отказа. Blue-green даёт мгновенный откат для кода, но не для данных: применённая миграция откатом версии не отменяется, поэтому изменения схемы делают совместимыми в обе стороны. Canary-выкатка бесполезна без сравнения метрик: пять процентов трафика, за которыми никто не смотрит, — это просто медленная выкатка. Долгое сосуществование версий увеличивает вероятность несовместимости.

Что мерить.

  • время выкатки и время отката;
  • долю выкаток с откатом;
  • сравнение ошибок и задержки между версиями;
  • длительность окна сосуществования.

Связано: OPS-01 CI/CD · EDGE-04 маршрутизация на границе · DATA-17 миграции схемы · REL-04 фича-флаги

Источники: Martin Fowler — BlueGreenDeployment · Martin Fowler — CanaryRelease · Google SRE Workbook — Canarying Releases · ByteByteGo — Top 5 Most-Used Deployment Strategies


OPS-03 · Окружения, тестовые данные и стенды#

Шаг W9

TL;DR. Окружение ценно ровно настолько, насколько оно похоже на прод. Расхождения не устраняются полностью — их нужно знать и держать в известных границах.

Проблема. «На тесте работало» — следствие того, что тестовое окружение отличается от прода объёмом данных, версиями зависимостей, конфигурацией, сетевыми задержками и нагрузкой. Отдельная беда — данные: без реалистичных данных не воспроизводятся ни производительность, ни крайние случаи, а копирование БД прода «как есть» — прямая утечка персональных данных.

Как работает.

  • Окружения различаются конфигурацией, а не сборкой (OPS-01). Всё, что отличается, должно быть перечислено явно. Иначе список расхождений неизвестен, и каждое из них может оказаться причиной.
  • Тестовые данные. Три способа, обычно вместе:
    • сгенерированные — безопасно, но не ловит реальные крайние случаи;
    • обезличенные данные из прода — реалистично, но требует надёжного обезличивания, а не «замены имён»;
    • синтетический поток по нагрузочному профилю.
  • Обезличивание должно сохранять статистические свойства — распределение размеров, длину строк, долю пустых значений, — иначе производительность на нём ничего не показывает.
  • Эфемерные стенды. Окружение на ветку, создаваемое из кода (OPS-06) и удаляемое после слияния, работает лучше вечного общего теста, который «кто-то опять сломал».
  • Проверки на проде — то, что нельзя воспроизвести иначе: canary-выкатка (OPS-02), dark launch, синтетический мониторинг (synthetic monitoring) ключевых сценариев, фича-флаги для внутренних пользователей.
  • Управление внешними зависимостями. Заглушки для чужих API дают воспроизводимость, песочницы поставщика — реалистичность; контрактные тесты (OPS-12) связывают одно с другим.

Trade-offs и режимы отказа. Полная копия прода дорога и всё равно не совпадает. Полезнее договориться, какие свойства должны совпадать (версии, схема, порядки объёмов), и проверять это. Общий стенд без владельца деградирует до состояния, в котором ему никто не верит. Обезличенные данные, из которых можно восстановить личность по совокупности полей, — утечка, оформленная как безопасная практика.

Что мерить.

  • время создания окружения;
  • число расхождений с продом в списке;
  • долю тестов, падающих только на стенде;
  • возраст тестовых данных;
  • время недоступности общего стенда.

Связано: OPS-01 CI/CD · OPS-12 тестирование · OPS-06 конфигурация и IaC · DATA-19 приватность данных

Источники: Martin Fowler — Test Data · Google — Testing on the Toilet: тестовые данные · Google SRE Workbook — Canarying Releases


OPS-04 · Bare metal, виртуальные машины, контейнеры#

Шаг W9

TL;DR. Три уровня изоляции с разной ценой и разной степенью защиты. Контейнер — это процесс с ограничениями, а не маленькая виртуальная машина.

Как работает.

  • Физический сервер (bare metal) — максимум производительности и предсказуемости, минимум гибкости. Оправдан для нагрузок, чувствительных к задержке и оборудованию.
  • Виртуальная машина — своё ядро и полноценная изоляция средствами процессора: нагрузки разных клиентов можно селить рядом. Плата — накладные расходы и минуты на запуск.
  • Контейнер — процесс основной операционной системы с изолированными namespaces (пространствами имён) и ограничениями ресурсов (cgroups). Запуск за миллисекунды, минимальные накладные расходы, но ядро общее: изоляция слабее. Для недоверенного кода это ограничение, и для него есть промежуточные решения с облегчённой виртуализацией.

Что действительно даёт контейнеризация. Главное не изоляция, а воспроизводимость: образ содержит приложение и его зависимости, поэтому окружение перестаёт быть переменной (OPS-03). Отсюда же одинаковый способ запуска для любого языка — то, на чём построены оркестраторы.

Практика образов. Минимальный базовый образ и многоэтапная сборка (multi-stage build): инструменты сборки не попадают в конечный образ. Фиксация базового образа по контрольной сумме, а не по подвижному тегу (SEC-10). Запуск не от root. Один процесс на контейнер. Никакого состояния внутри — оно во внешних хранилищах (ARCH-12).

Три уровня изоляции

Уровень Изоляция Запуск Когда уместен
Физический сервер Полная Минуты и часы Чувствительность к оборудованию и задержке
Виртуальная машина Своё ядро Минуты Недоверенные соседи, разные операционные системы
Контейнер Общее ядро Миллисекунды Основной вариант для собственных сервисов
Облегчённая виртуализация Своё ядро при быстром старте Секунды Недоверенный код там, где нужна скорость

Trade-offs и режимы отказа. Ограничение памяти приводит к жёсткому уничтожению процесса (OOM kill) без внятного сообщения. Рантаймы должны знать свой лимит, иначе сборщик мусора ориентируется на память всей машины (PERF-10). CPU throttling (ограничение процессорного времени) задерживает потоки и портит хвост распределения задержки. Раздутые образы замедляют выкатку и увеличивают поверхность атаки.

Что мерить.

  • размер образа и время запуска;
  • число OOM kill;
  • задержки из-за CPU throttling;
  • долю образов на актуальном базовом образе.

Связано: OPS-05 Kubernetes · ARCH-12 cloud native · SEC-10 цепочка поставок · PERF-10 сборка мусора

Источники: Docker — Best practices for building images · Linux — namespaces и cgroups · ByteByteGo — Big Misconceptions about Bare Metal, Virtual Machines, and Containers · ByteByteGo — Is Docker Still Relevant? · ByteByteGo — System Design: Why Is Docker Important?


OPS-05 · Kubernetes: что решает и чего стоит#

Шаг W9

TL;DR. Система, которая приводит фактическое состояние кластера к описанному. Решает реальные задачи и приносит собственную сложность, сопоставимую с задачами, которые решает.

Проблема. Контейнеры сами по себе не отвечают на вопросы:

  • где их запускать;
  • что делать при падении узла;
  • как обновлять без простоя;
  • как им находить друг друга;
  • как раздавать конфигурацию и секреты.

До оркестратора это решалось скриптами, каждый раз своими.

Ключевая идея — декларативность. Вы описываете желаемое состояние, контроллеры непрерывно сравнивают его с фактическим и устраняют разницу (reconciliation loop). Отсюда самовосстановление: узел упал — экземпляры пересозданы в другом месте, без участия человека.

Что даёт из коробки.

  • планирование по ресурсам;
  • проверки liveness (жизнеспособности) и readiness (готовности) (REL-05);
  • постепенное обновление и откат (OPS-02);
  • service discovery и балансировку (EDGE-08);
  • конфигурацию и секреты отдельно от образа (OPS-06);
  • автомасштабирование (OPS-11);
  • точку входа для внешнего трафика (EDGE-04).

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

Когда оправдан. Много сервисов, частые выкатки, потребность в автомасштабировании, несколько команд с общей платформой. Когда нет: три сервиса и редкие выкатки обслуживаются управляемыми контейнерными сервисами или простыми виртуальными машинами дешевле и понятнее. Управляемый кластер снимает часть работы, но не необходимость понимать модель.

Альтернативы

Вариант Когда Цена
Виртуальные машины и скрипты выкатки Единицы сервисов, редкие выкатки Ручные процедуры, расхождение серверов
Управляемые контейнерные сервисы До десятка сервисов, стандартные потребности Меньше гибкости, привязка к провайдеру
Управляемый Kubernetes Много сервисов, несколько команд, автомасштабирование Изучение модели, обновления, отладка через слои
Собственный кластер Свой ЦОД, особые требования Выделенные люди на эксплуатацию

Trade-offs и режимы отказа. Неверно заданные requests и limits (запросы и лимиты ресурсов) приводят к вытеснению нужных экземпляров и OOM kill (OPS-04). Автомасштабирование по CPU бесполезно, когда узкое место — БД (OPS-11). Конфигурация в манифестах — такой же код, и ошибка в ней распространяется мгновенно на весь кластер.

Что мерить.

  • число перезапусков и вытеснений;
  • время от изменения манифеста до готовности;
  • утилизацию против запрошенных ресурсов;
  • время обновления кластера.

Связано: OPS-04 контейнеры · OPS-11 ёмкость и автоскейлинг · OPS-06 конфигурация · REL-05 health checks

Источники: Kubernetes — Concepts · Kubernetes — Managing resources for containers · ByteByteGo — Kubernetes Explained in 6 Minutes | k8s Architecture · ByteByteGo — Why is Kubernetes Popular | What is Kubernetes?


OPS-06 · Конфигурация и инфраструктура как код#

Шаг W9

TL;DR. Инфраструктура и конфигурация описываются в репозитории и применяются автоматически. Иначе состояние прода известно только тем, кто его настраивал, и то приблизительно.

Проблема. Ручная настройка не воспроизводится: восстановить окружение после аварии, поднять копию для теста или объяснить, чем прод отличается от стенда, невозможно. Со временем серверы расходятся между собой (configuration drift), и появляются машины, которые «трогать нельзя». Конфигурация, зашитая в сборку, требует пересборки на каждое изменение параметра.

Как работает.

  • Infrastructure as Code (IaC, инфраструктура как код). Ресурсы описаны декларативно, инструмент вычисляет разницу с фактическим состоянием и применяет её. Изменения проходят ревью, а предварительный просмотр плана показывает, что произойдёт, — это важнее самой автоматизации.
  • Одноразовость вместо ухода (immutable infrastructure). Экземпляр не чинят и не донастраивают — его пересоздают из описания. Это же свойство делает возможным восстановление после аварии.
  • Состояние инструмента (state file) — критический файл: он описывает, чем инструмент управляет. Хранится удалённо, с блокировкой и версиями.
  • Конфигурация приложения — снаружи (ARCH-12): переменные окружения или конфигурационные объекты, один образ на все окружения.
  • Секреты — не конфигурация (SEC-08): отдельное хранилище, отдельные права, ротация.
  • Динамические параметры (лимиты, флаги, пороги) меняются без выкатки, но остаются под контролем: версионирование, ревью, аудит и, главное, откат — конфигурация ломает прод не реже кода.

Trade-offs и режимы отказа. Ручные правки поверх кода порождают расхождение (drift): следующее применение внезапно откатывает чужие изменения. Отсюда правило «только через код» и регулярная проверка на расхождение. Один общий репозиторий инфраструктуры делает применение изменений очередью между командами. Слишком широкие права у инструмента превращают ошибку в удаление ресурсов прода; здесь помогают раздельные состояния по средам и защита от удаления.

Что мерить.

  • долю ресурсов под управлением кода;
  • расхождение факта и описания;
  • время создания окружения с нуля;
  • число ручных изменений в проде;
  • число инцидентов, вызванных изменением конфигурации.

Связано: OPS-03 окружения · SEC-08 секреты · OPS-05 Kubernetes · REL-04 фича-флаги

Источники: HashiCorp — Terraform: infrastructure as code · The Twelve-Factor App — Config · Google SRE Book, гл. 8 «Release Engineering»


OPS-07 · Observability: метрики, логи, трассировка#

Шаг W9

TL;DR. Observability (наблюдаемость) — способность ответить на вопрос о поведении системы, который не был предусмотрен заранее. Три вида данных дополняют друг друга и не заменяют.

Проблема. Пользователь жалуется, что «всё медленно». Дашборд показывает нормальную загрузку. Ошибок нет. Где искать? Без сквозного контекста ответ добывается перебором гипотез, а в распределённой системе перебор бесконечен. Мониторинг отвечает на заранее заданные вопросы, observability — на незаданные.

Три сигнала.

  • Метрики — числовые ряды: дёшевы, агрегированы, годятся для дашбордов и алертов. Для сервисов минимальный набор — частота запросов, доля ошибок, распределение времени ответа (RED); для ресурсов — утилизация, насыщенность, ошибки (USE). Смотреть на перцентили, не на среднее (PERF-02).
  • Логи — события с контекстом: дороги, но незаменимы для деталей. Структурированные (пары «поле — значение»), с идентификатором запроса, без персональных данных и секретов (SEC-12).
  • Трассировка (tracing) — путь одного запроса через все сервисы с временем каждого участка. В распределённой системе это единственный способ увидеть, где потерялось время. Требует сквозной передачи контекста (context propagation) — через HTTP-заголовки и через сообщения в очередях, иначе цепочка обрывается на первой асинхронной границе.

Что связывает всё вместе. Единый идентификатор запроса во всех трёх сигналах: от аномалии на графике — к трассировке медленного запроса — к логам конкретного шага. Без этой связи три системы существуют по отдельности, и переход между ними делается вручную.

Практика. Инструментирование через общий стандарт (OpenTelemetry) вместо привязки к поставщику. Полезные метки — версия, окружение, эндпоинт, но не идентификаторы пользователей (OPS-08). Наблюдение за симптомами, видимыми пользователю, а не только за ресурсами. Дашборд на сервис, отвечающий на вопрос «здоров ли он», плюс дашборд на сценарий, отвечающий «работает ли то, за что платят».

Три сигнала

Сигнал На какой вопрос отвечает Стоимость Главное ограничение
Метрики Что происходит и насколько плохо Низкая Кардинальность меток
Логи Что случилось в этом конкретном случае Высокая Объём и стоимость поиска
Трассировка Где потерялось время в цепочке Средняя Нужен сквозной контекст, иначе цепочка рвётся

Trade-offs и режимы отказа. Observability стоит денег и нагрузки — иногда сопоставимо со стоимостью самой системы (OPS-08). Инструментирование добавляет задержку. Система мониторинга не должна зависеть от наблюдаемой системы: во время аварии мониторинг нужнее всего.

Что мерить.

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

Связано: OPS-08 стоимость observability · OPS-09 SLO · OPS-13 отладка в проде · SEC-12 аудит

Источники: OpenTelemetry — Documentation · Google SRE Book, гл. 6 «Monitoring Distributed Systems» · Brendan Gregg — USE Method · Tom Wilkie — RED method


OPS-08 · Стоимость observability#

Шаг W10

TL;DR. Данные о системе легко становятся дороже самой системы. Три рычага: кардинальность метрик, сэмплирование трассировки, срок хранения логов.

Проблема. Observability подключают, не считая её стоимость, и через год счёт за неё сопоставим со счётом за вычисления. Одновременно с ростом объёма падает польза. В терабайтах логов ищут дольше, дашборды с сотнями графиков никто не читает, а система мониторинга сама начинает падать под нагрузкой.

Три рычага.

  • Кардинальность метрик — главный источник неприятностей. Число рядов равно произведению количеств значений всех меток. Метка с идентификатором пользователя или запроса умножает объём на миллионы и выводит систему из строя — это самая частая авария мониторинга. Правило: метки только с ограниченным набором значений; всё остальное — в логи и трассировку, которые для этого и предназначены.
  • Сэмплирование трассировки. Хранить все трассы дорого и не нужно. Два подхода:
    • head-based sampling (решение в начале) — просто, но теряет редкие интересные случаи;
    • tail-based sampling (решение в конце, по результату) — сохранять ошибочные и медленные, отбрасывать обычные; дороже в реализации, но гораздо полезнее.
  • Срок хранения по уровням. Подробные данные — дни, агрегаты — месяцы, ключевые показатели — годы. Логи отладочного уровня в проде обычно отключены и включаются точечно.

Что ещё помогает.

  • уровни логирования, управляемые без выкатки;
  • отказ от логирования успешных операций там, где есть метрика;
  • агрегация повторяющихся сообщений;
  • хранение редко используемых данных в дешёвом холодном хранилище.

Trade-offs и режимы отказа. Цена экономии обнаруживается в момент, когда данных не хватило для расследования. Поэтому решения о сокращении принимают по фактическому использованию, а не по ощущению: какие метрики читались дашбордами и алертами за квартал. Tail-based sampling требует буферизации трасс, что усложняет конвейер. Слишком агрессивная фильтрация логов делает воспроизведение инцидента невозможным.

Что мерить.

  • стоимость observability относительно стоимости инфраструктуры;
  • число активных рядов и его рост;
  • объём логов на запрос;
  • долю метрик, которые не используются ни одним дашбордом или алертом.

Связано: OPS-07 observability · PERF-11 стоимость · DATA-19 retention · DATA-02 time-series хранилища

Источники: Prometheus — Naming and cardinality · OpenTelemetry — Sampling · Google SRE Workbook — Monitoring


OPS-09 · SLI, SLO и бюджет ошибок#

Шаг W0

TL;DR. Показатель (SLI) измеряет качество глазами пользователя, цель (SLO) задаёт допустимый уровень, разница между ними — бюджет ошибок (error budget), который можно тратить осознанно.

Проблема. «Система должна работать хорошо» не позволяет ни принять решение, ни разрешить спор. Сколько надёжности нужно? Ответ «максимум» неверен: каждая девятка стоит кратно дороже предыдущей. Стопроцентная надёжность недостижима и не нужна — пользователь всё равно ограничен своей сетью и устройством. Без числа спор о том, выкатывать ли рискованное изменение, решается громкостью голоса.

Как работает.

  • Показатель (SLI, Service Level Indicator) — измерение того, что чувствует пользователь: доля успешных запросов, доля запросов быстрее порога, доля успешно завершённых сценариев. Измеряется как можно ближе к пользователю; загрузка CPU — не SLI.
  • Цель (SLO, Service Level Objective) — значение за окно: «99.9 % запросов успешны за 28 дней». Ставится по потребности пользователей и стоимости, а не по достижимому максимуму.
  • Бюджет ошибок — разрешённая доля неуспеха: 99.9 % за месяц дают около 43 минут. Это не запас прочности, а ресурс: пока бюджет есть, команда выкатывает и рискует; когда исчерпан — приоритет переходит к надёжности. Так технический спор превращается в правило, согласованное заранее.
  • Соглашение (SLA, Service Level Agreement) — внешнее обязательство с последствиями. Внутреннюю цель ставят строже SLA, иначе нарушение обнаруживается вместе со штрафом.
  • Немного целей. Два-три показателя на сервис, покрывающих основные сценарии. Двадцать целей означают, что нет ни одной.

Trade-offs и режимы отказа. Цель, поставленная выше реально нужной, тратит деньги и запрещает изменения. Цель, которую ни разу не нарушали, скорее всего занижена и ничего не регулирует. Показатель, усреднённый по всем эндпоинтам, скрывает отказ важного и редкого сценария: считать нужно по сценариям, а не по общему числу запросов. И главное: бюджет ошибок работает, только если правило «бюджет исчерпан — останавливаем изменения» действительно исполняется.

Что мерить.

  • текущее значение показателей;
  • остаток бюджета и скорость его расходования (burn rate);
  • число нарушений цели за квартал;
  • долю инцидентов, потративших заметную долю бюджета.

Связано: OPS-10 алертинг · OPS-07 observability · REL-06 отказоустойчивость · W0

Источники: Google SRE Book, гл. 4 «Service Level Objectives» · Google SRE Workbook — Implementing SLOs · Alex Hidalgo — Implementing Service Level Objectives


OPS-10 · Алертинг, дежурства, постмортемы#

Шаг W9

TL;DR. Алерт должен означать «нужно вмешаться прямо сейчас». Всё остальное — не алерт, а информация, и её место на дашборде.

Проблема. Стандартный путь: алерты заводят на каждую аномалию, дежурного будят по ночам из-за всплеска загрузки, который прошёл сам, и через месяц уведомления перестают читать. Alert fatigue (усталость от оповещений) — не следствие плохой дисциплины, а предсказуемый результат оповещений, не требующих действия. При этом настоящая авария теряется среди шума.

Как работает.

  • Алерты по симптомам, а не по причинам. «Доля ошибок оформления заказа выше порога» будит по делу; «загрузка CPU 90 %» — это, возможно, нормальная работа. Причины ищут после того, как симптом подтвердил проблему.
  • Основа — расход бюджета ошибок (OPS-09): оповещение срабатывает, когда бюджет тратится темпом (burn rate), который ведёт к нарушению цели. Быстрое сжигание — немедленный вызов, медленное — задача на рабочий день.
  • У каждого алерта есть инструкция (runbook). Что происходит, что проверить, что сделать, кого звать. Алерт без инструкции превращает дежурство в исследование с нуля.
  • Дежурство (on-call). Разумная нагрузка (единицы вызовов за смену), компенсация, право остановить поток работ ради устранения причин, ротация. Дежурный, разбуженный трижды за ночь, не примет верное решение на четвёртый раз.
  • Постмортем без поиска виноватых (blameless postmortem). Цель — понять, как система и процессы допустили ошибку, а не кто нажал. Человеческая ошибка — это симптом устройства системы. Разбор ценен, только если из него выходят задачи со сроками и владельцами.

Trade-offs и режимы отказа. Слишком чувствительные пороги дают шум, слишком грубые — пропуск. Практика — оповещать по устойчивому нарушению, а не по мгновенному значению. Полностью автоматическое восстановление скрывает проблему: если что-то чинится само сто раз в день, об этом нужно знать. Постмортемы, которые пишут и не читают, тратят время без результата — их ценность в выполненных задачах.

Что мерить.

  • число оповещений на смену и долю потребовавших действия;
  • время до реакции и до восстановления;
  • долю инцидентов с постмортемом;
  • долю задач из постмортемов, выполненных в срок.

Связано: OPS-09 SLO · OPS-07 observability · OPS-13 отладка в проде · REL-10 chaos engineering

Источники: Google SRE Book, гл. 6 и 15 «Postmortem Culture» · Google SRE Workbook — Alerting on SLOs · Google SRE Book, гл. 11 «Being On-Call»


OPS-11 · Ёмкость и автомасштабирование#

Шаг W1

TL;DR. Оценки из W1 превращаются в ресурсы здесь. Автомасштабирование помогает только там, где узкое место действительно эластично.

Проблема. Сколько нужно ресурсов? Ответ «поставим автомасштабирование» неполон: масштабирование реагирует минутами и ограничено квотами. А если упирается общая БД, добавление экземпляров приложения делает хуже: растёт конкуренция за соединения (PERF-06).

Как работает.

  • Знать ёмкость единицы. Нагрузочное испытание (OPS-12) даёт число: сколько запросов держит один экземпляр при приемлемой задержке. Без этого числа планирование — гадание.
  • Планирование по спросу. Прогноз нагрузки, помноженный на запас, плюс отдельно — известные пики (распродажи, рассылки, сезон). Пик закладывается заранее, а не отдаётся автомасштабированию.
  • Показатель масштабирования. Загрузка CPU работает, только когда узкое место в вычислениях. Чаще правильнее масштабировать по длине очереди или числу одновременных запросов — величинам, прямо связанным с ожиданием пользователя.
  • Асимметрия. Расширяться быстро, сжиматься медленно: колебания дороже небольшого перерасхода.
  • Пределы. Верхняя граница защищает от разорительного разрастания при ошибке; нижняя — от холодного старта после затишья.
  • Static stability (статическая стабильность, REL-06): при аварии control plane (управляющий слой) может быть недоступен, поэтому критичная ёмкость резервируется заранее, а не запрашивается в момент отказа.
  • Что не масштабируется автоматически. БД, квоты внешних API, лицензии, пулы соединений. Обычно узкое место как раз там.

По какому показателю масштабировать

Показатель Когда подходит Когда обманывает
Загрузка CPU Узкое место в вычислениях Нагрузка упирается в ожидание или в БД
Число одновременных запросов Общий случай для сервисов При медленной внешней зависимости
Длина очереди и время ожидания Асинхронная обработка Требует ограниченной очереди
Расписание Предсказуемые пики: рассылки, распродажи Внезапные всплески

Trade-offs и режимы отказа. Масштабирование по CPU при узком месте в БД усиливает деградацию. Слишком быстрая реакция даёт колебания. Автомасштабирование без ограничений превращает всплеск трафика (или цикл повторов) в счёт на порядок больше обычного (PERF-11). Масштабирование потребителей очереди без учёта ёмкости нижележащих систем переносит перегрузку вниз (MSG-09).

Что мерить.

  • ёмкость на экземпляр;
  • запас относительно пика;
  • время реакции масштабирования;
  • частоту срабатываний;
  • стоимость на единицу нагрузки;
  • долю времени у верхнего предела.

Связано: OPS-12 нагрузочное тестирование · PERF-08 методика нагрузочного тестирования · PERF-11 стоимость · DIST-01 масштабирование

Источники: Google SRE Book, гл. 18 «Software Engineering in SRE» и гл. 11 про планирование ёмкости · AWS — Auto Scaling best practices · Kubernetes — Horizontal Pod Autoscaling


OPS-12 · Тестирование#

Шаг W9

TL;DR. Много быстрых тестов внизу, мало медленных наверху. Для распределённых систем ключевую роль играют контрактные тесты — они заменяют половину сквозных.

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

Уровни.

  • Модульные (unit) — правила и крайние случаи, миллисекунды, без внешних зависимостей. Их много, и как раз они делают рефакторинг безопасным (ARCH-03).
  • Интеграционные — код вместе с реальной БД или очередью в контейнере. Проверяют то, что заглушки не проверяют: запросы, транзакции, миграции.
  • Контрактные (NET-18) — ключевой уровень для распределённых систем: потребитель объявляет свои ожидания, поставщик прогоняет их у себя (consumer-driven contracts). Несовместимое изменение ловится в конвейере поставщика, без поднятия обеих систем.
  • Сквозные (end-to-end) — единицы штук на критические сценарии: регистрация, оформление заказа, оплата. Всё остальное покрывается ниже.
  • Нагрузочные (PERF-08) — отдельный вид, отвечающий на вопрос о ёмкости, а не о корректности.
  • Виды API-проверок — функциональные, на безопасность, на совместимость версий, дымовые (smoke) после выкатки, — раскладываются по этим же уровням.

Что делает набор тестов полезным.

  • детерминированность: нестабильный тест хуже отсутствующего, потому что обесценивает весь прогон;
  • независимость от порядка и от общего состояния;
  • понятная диагностика падения;
  • скорость обратной связи — она важнее полноты покрытия: набор, идущий десять минут, реально используют.

Уровни

Уровень Что ловит Скорость Сколько нужно
Модульные Правила и крайние случаи Миллисекунды Много
Интеграционные Запросы, транзакции, миграции Секунды Средне
Контрактные Несовместимые изменения API Секунды По одному на границу
Сквозные Критические сценарии целиком Минуты Единицы штук
Нагрузочные Ёмкость и поведение под нагрузкой Часы Отдельным процессом

Trade-offs и режимы отказа. Погоня за процентом покрытия даёт тесты на геттеры и не даёт тестов на крайние случаи. Тесты, повторяющие реализацию, ломаются при каждом рефакторинге и мешают менять код. Общий тестовый стенд превращает набор в очередь между командами (OPS-03).

Что мерить.

  • время прогона по уровням;
  • долю нестабильных тестов;
  • долю дефектов, найденных уже в проде;
  • число несовместимых изменений, пойманных контрактными тестами.

Связано: OPS-03 окружения · NET-18 контракты · PERF-08 нагрузочное тестирование · OPS-01 CI/CD

Источники: Martin Fowler — Test Pyramid · Pact — Consumer-driven contracts · Testcontainers · ByteByteGo — Top 9 Most Popular Types of API Testing


OPS-13 · Отладка и диагностика в проде#

Шаг W9

TL;DR. В проде нельзя поставить точку останова. Диагностика строится на сигналах, гипотезах и инструментах, работающих на живой системе.

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

Метод.

  1. Определить симптом в терминах пользователя и его границы: все или часть, все эндпоинты или один, с какого момента, совпадает ли с выкаткой или ростом нагрузки. Половина расследований заканчивается здесь: изменение выкатили десять минут назад.
  2. Сузить участок по трассировке (OPS-07): где растёт время: в сервисе, в БД, во внешнем вызове, в ожидании.
  3. Проверить ресурсы методом USE (utilization, saturation, errors): утилизацию, насыщенность и ошибки для CPU, памяти, диска, сети, пулов.
  4. Сформулировать гипотезу и проверить дешёвым способом — сравнением с базовой линией, выборкой логов, снимком состояния.

Инструменты живой системы.

  • профилирование в проде с малыми накладными расходами (PERF-09);
  • снимки стеков потоков и кучи (thread dump, heap dump);
  • динамическая трассировка ядра и приложения — eBPF и родственные инструменты;
  • подробное логирование, включаемое точечно для доли трафика;
  • отладочные эндпоинты, доступные только внутри.

Чего не делать.

  • менять несколько вещей сразу: причина останется неизвестной, даже если стало лучше;
  • перезапускать до снятия диагностики: перезапуск уничтожает состояние, в котором единственное объяснение;
  • отлаживать в проде то, что воспроизводится на стенде.

Trade-offs и режимы отказа. Диагностические инструменты сами создают нагрузку — профилирование под пиком может усугубить ситуацию. Точечное включение подробных логов требует механизма, добавленного заранее (OPS-06): во время инцидента его не выкатить. Отладочные эндпоинты — поверхность атаки (SEC-06).

Что мерить.

  • время от оповещения до локализации;
  • долю инцидентов, диагностированных по имеющимся данным без дополнительной выкатки;
  • накладные расходы инструментов.

Связано: OPS-07 observability · OPS-10 алертинг · PERF-09 профилирование · PERF-02 перцентили

Источники: Brendan Gregg — Systems Performance и USE Method · Google SRE Book, гл. 12 «Effective Troubleshooting» · ByteByteGo — Debugging Like A Pro


OPS-14 · DevOps, SRE, Platform Engineering: роли#

Справка

Коротко. Три ответа на один вопрос — как связать разработку и эксплуатацию.

  • DevOps — культура и практики: одна ответственность за код и его работу в проде, автоматизация, короткие циклы. Это не должность и не отдел; «отдел DevOps» обычно означает переименованных администраторов.
  • SRE (Site Reliability Engineering) — конкретная реализация с инженерным уклоном. Надёжность — продуктовая характеристика, измеряемая целями и бюджетом ошибок (OPS-09); доля ручной работы ограничена; есть право остановить выкатки при исчерпании бюджета.
  • Platform Engineering — внутренняя платформа как продукт для команд разработки: типовые пути (golden paths) для выкатки, observability (наблюдаемости) и инфраструктуры, которыми пользуются добровольно, потому что удобно.

Что из этого важно для дизайна. Эксплуатационные свойства — чья-то явная ответственность, и она должна быть названа на шаге W9. Система, у которой нет владельца в проде, деградирует независимо от качества архитектуры.

Источники: Google SRE Book — Introduction · Team Topologies · ByteByteGo — DevOps vs SRE vs Platform Engineering | Clear Big Misconceptions


OPS-15 · Монорепозиторий против нескольких репозиториев#

Справка

Коротко. Выбор про то, где проходит граница атомарного изменения.

Монорепозиторий Несколько репозиториев
Изменение через несколько сервисов Один коммит Согласование нескольких
Общий код Прямая ссылка, актуален без обновления версий Версионированные пакеты
Инструменты Нужна сборка с учётом зависимостей Стандартные
Права доступа Сложнее ограничить Естественно по репозиториям
Порог входа Большой объём Понятная граница

Что важно. Монорепозиторий (monorepo) не отменяет границ (ARCH-02) — он лишь снимает организационные издержки; границы обеспечиваются владельцами каталогов и проверками зависимостей. Он же требует инструментов, собирающих и тестирующих только затронутое: без них конвейер прогоняет всё на каждое изменение. Несколько репозиториев дают простоту ценой согласованных изменений — и это ровно та цена, которую платят при неверно проведённых границах.

Источники: Google — Why Google Stores Billions of Lines of Code in a Single Repository (CACM 2016) · Bazel · ByteByteGo — Why Google and Meta Put Billion Lines of Code In 1 Repository?


OPS-16 · Релиз мобильных приложений#

Справка

Коротко. Мобильный клиент — единственная часть системы, которую нельзя откатить: у пользователей остаётся установленная версия, а публикация занимает часы или дни.

Следствия для дизайна.

  • Старые версии живут годами. Совместимость API нужно поддерживать дольше, чем в вебе (NET-17); нужен механизм минимально поддерживаемой версии с принудительным обновлением.
  • Логика переносится на сервер. Всё, что может измениться, лучше держать серверным: клиент, ушедший на устройства, зафиксирован.
  • Поэтапная раскатка (staged rollout) через магазин приложений — аналог canary-выкатки; за отказами нужно наблюдать по версиям.
  • Фича-флаги вместо релизов (REL-04): код выкатывается заранее, функция включается серверным переключателем, что возвращает возможность отката.

Источники: Android — Staged rollouts · Apple — Phased release for automatic updates · ByteByteGo — Do You Know How Mobile Apps Are Released?


OPS-17 · Когнитивная нагрузка команды#

Шаг W4

TL;DR. Команда удерживает ограниченное число предметных областей. Считать надо домены, а не сервисы: сервисов может быть много при одном домене, и это нормально.

Проблема. Команда отвечает за четыре несвязанные области. Переключение между ними стоит дороже самой работы, глубины нет ни в одной, новичок входит полгода. Обсуждают это обычно как проблему людей — «не хватает рук», — хотя по существу это свойство разреза: границы провели, не спросив, кто будет их держать.

Как работает. Нагрузка бывает трёх видов (Skelton, Pais, Team Topologies):

Вид Что это Что с ней делать
Внутренняя (intrinsic) Сложность самой технологии: язык, хранилище, протокол Снижается обучением и опытом
Внешняя (extraneous) Окружение: ручные шаги, неудобные инструменты, согласования Убирать полностью — это чистые потери
Уместная (germane) Предметная область, ради которой команда существует Ограничивать числом доменов — ради неё и освобождают место

Признак — число доменов, а не сервисов. Десять сервисов одного домена команда держит спокойно; два сервиса из двух несвязанных доменов — уже тяжело. Практический ориентир: один-два домена на команду, три — предел, дальше глубина теряется во всех.

Когда применять. При выборе границ (D-02, D-05) и при перераспределении владения. Когда нет: одна команда на всю систему — тогда вопрос не в нагрузке, а в том, что разрез преждевременен.

Альтернативы

Что делают Когда работает Цена
Сузить зону команды до одного-двух доменов Команд хватает Нужны люди
Снять внешнюю нагрузку: автоматизация, платформа Потери видны и измеримы Платформенная команда — тоже команда
Оставить как есть и признать Штат мал, выбора нет Записать, чем жертвуют: глубиной в каком домене

Trade-offs и режимы отказа. «Одна команда — один домен» недостижимо при малом штате, и делать вид, что достижимо, хуже, чем признать перегрузку и назвать домен, которым жертвуют. Обратная ошибка — дробить команды под каждый домен: получаются команды, которых не хватает на дежурство, и разрез упирается в дисквалификатор «сервисов больше, чем команд».

Что мерить.

  • число доменов на команду;
  • время до первого самостоятельного изменения новичка в каждом из них;
  • долю задач, требующих согласования с другой командой, — D-02 считает её же как связность изменений;
  • долю времени на внешнюю нагрузку: ручные шаги и ожидание.

Связано: OPS-14 роли: DevOps, SRE, Platform · ARCH-01 монолит и микросервисы · ARCH-02 границы сервисов · OPS-15 монорепозиторий

Источники: Skelton, Pais — Team Topologies · Melvin Conway — How Do Committees Invent? · Google SRE Book — Introduction