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. В проде нельзя поставить точку останова. Диагностика строится на сигналах, гипотезах и инструментах, работающих на живой системе.
Проблема. Проблема воспроизводится только под нагрузкой, только на данных прода или раз в сутки. Классическая отладка недоступна: остановить процесс нельзя, добавить логирование — значит выкатить новую версию и ждать повторения.
Метод.
- Определить симптом в терминах пользователя и его границы: все или часть, все эндпоинты или один, с какого момента, совпадает ли с выкаткой или ростом нагрузки. Половина расследований заканчивается здесь: изменение выкатили десять минут назад.
- Сузить участок по трассировке (OPS-07): где растёт время: в сервисе, в БД, во внешнем вызове, в ожидании.
- Проверить ресурсы методом USE (utilization, saturation, errors): утилизацию, насыщенность и ошибки для CPU, памяти, диска, сети, пулов.
- Сформулировать гипотезу и проверить дешёвым способом — сравнением с базовой линией, выборкой логов, снимком состояния.
Инструменты живой системы.
- профилирование в проде с малыми накладными расходами (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