DDD-спецификация: гайд для DevOps-инженера
DevOps-гайд по DDD-спецификации: подготовка PostgreSQL и Kafka, deploy в Kubernetes, мониторинг агрегатов и Saga, плейбуки на инциденты.
DDD DevOps: введение
DDD DevOps — devOps-инженер участвует в 6 из 16 разделов DDD-спецификации. Его задача -- обеспечить развертывание, эксплуатацию и наблюдаемость системы, спроектированной по DDD.
Разделы, содержащие DevOps-блоки:
| Раздел | Тема | Фокус DevOps |
|---|---|---|
| 1 | Bounded Context | Развертывание, сетевые связи, секреты |
| 3.4 | Схема базы данных | PostgreSQL, миграции, бекапы, мониторинг БД |
| 8 | Domain Events | Kafka, Outbox, DLQ, Schema Registry |
| 12 | Saga / Process Manager | Зависшие процессы, retry storm, tracing |
| 14 | Интеграции | Конфигурация подключений, health checks, SLA |
| 16 | Нефункциональные требования | Масштабирование, алерты, таблица метрик |
Полная структура шаблона: Use Case спецификация
1. Развертывание
Источник: раздел 1 -- Bounded Context.
Диаграмма C1 (System Context) -- карта того, что нужно развернуть и связать.
Граница развертывания. Один Bounded Context = один deployable unit. Из этого следует: один Docker-образ, один Helm chart, отдельный namespace в Kubernetes. Не смешивать контексты в одном деплойменте -- это нарушает автономность.
Сетевые связи. Каждая стрелка на диаграмме C1 -- сетевое соединение. Для каждого определить: DNS-имя сервиса, порт, NetworkPolicy в Kubernetes, TLS-сертификат. Если стрелка пересекает границу кластера -- Ingress или Gateway.
Service discovery. Kubernetes DNS для внутренних сервисов (формат <service>.<namespace>.svc.cluster.local). При использовании service mesh (Istio) -- дополнительно настроить VirtualService и DestinationRule.
Секреты. API-ключи, пароли БД, credentials для внешних систем -- в Kubernetes Secrets или HashiCorp Vault. Никогда в коде или ConfigMap. Ротация секретов без рестарта (Vault Agent или Sealed Secrets).
Environments. Dev / staging / prod -- для каждого окружения свои URL внешних систем, размеры ресурсов, количество реплик. Конфигурация через Helm values или Kustomize overlays.
2. База данных
Источник: раздел 3.4 -- Схема базы данных.
PostgreSQL. Настройки: max_connections (с учетом пула + PgBouncer), shared_buffers (25% RAM), work_mem (для сортировок и JOIN). Размер диска с запасом x3 от текущего объема.
Миграции. Flyway (или Liquibase) -- скрипты хранятся в репозитории. Применяются автоматически при деплое, до старта приложения. Init-контейнер в Kubernetes запускает миграции перед основным контейнером. Миграции должны быть идемпотентны и обратимы.
Бекапы. Ежедневный pg_dump или WAL-архивирование для point-in-time recovery. Тестировать восстановление ежемесячно. Outbox-таблица (domain_events_outbox) растет быстро -- cron job для очистки опубликованных событий старше 7 дней. Audit log хранится отдельно (retention >= 1 год).
Read-реплики. При высокой нагрузке на чтение -- streaming replication. Запросы SearchOrders направлять на реплику. Мониторить replication lag (алерт при задержке > 1 сек).
Connection pooling. PgBouncer перед PostgreSQL. Режим transaction для максимальной утилизации соединений. HikariCP на стороне приложения -- maximumPoolSize=20, connectionTimeout=5000ms.
Мониторинг БД. pg_stat_statements для обнаружения медленных запросов. Отслеживать: размер таблиц, количество активных соединений, replication lag, bloat (VACUUM). Индекс orders(status, customer_id, created_at) покрывает основные фильтры -- проверять его использование через EXPLAIN ANALYZE.
3. Kafka и события
Источник: раздел 8 -- Domain Events.
Топик order-events. Параметры: partitions >= 3 (масштабирование consumer-ов), replication.factor = 3 (отказоустойчивость), retention.ms = 7 дней (хранение сообщений). Partition key = orderId -- гарантирует порядок событий одного заказа.
Outbox и CDC. Два варианта доставки событий из outbox-таблицы в Kafka:
- Debezium + Kafka Connect -- CDC на уровне WAL, минимальная задержка.
- Polling job -- приложение опрашивает outbox каждые 100ms.
Независимо от выбора, очистка outbox обязательна: cron job удаляет опубликованные события старше 7 дней.
Dead Letter Queue (DLQ). Топик order-events-dlq для сообщений, которые consumer не смог обработать. Алерт при появлении любого сообщения в DLQ. Дашборд для просмотра и ручного re-processing.
Мониторинг Kafka. Consumer lag -- алерт если > 1000 сообщений. Throughput (messages/sec) -- базовая метрика нагрузки. Ошибки сериализации -- немедленный алерт (возможна несовместимость схем).
Schema Registry. Confluent Schema Registry для валидации backward compatibility событий. Новые поля добавлять, старые не удалять. Политика совместимости: BACKWARD.
4. Saga-мониторинг
Источник: раздел 12 -- Сложные процессы (Saga / Process Manager).
Saga -- источник операционных проблем. Два процесса: обработка заказа (резерв - оплата - доставка) и возврат средств. Каждый требует наблюдаемости.
Зависшие Saga. Таблица saga_state -- если запись в статусе RUNNING более 10 минут, срабатывает алерт. Дашборд с текущим состоянием всех активных Saga.
DLQ для Saga. Сообщения, которые Saga не смогла обработать, попадают в DLQ. Дашборд + алерт + инструмент для ручного повтора.
Retry storm. Если внешняя система (Склад, Оплата) упала, все Saga одновременно начинают retry. Защита: rate limiting на исходящие запросы + exponential backoff с jitter. Без jitter retry-и синхронизируются и создают пики нагрузки.
Distributed tracing. Jaeger (или Zipkin) с correlationId = orderId, проходящим через все шаги Saga. Позволяет отследить путь одного заказа через Склад, Оплату и Доставку.
Метрика компенсаций. saga_compensations_total -- если метрика растет, внешние системы нестабильны. Использовать как ранний индикатор деградации.
Runbook. Для каждого типа сбоя -- документированные ручные действия: как найти зависшую Saga в БД, перезапустить конкретный шаг, выполнить компенсацию вручную (например, снять резерв на складе через API).
5. Интеграции
Источник: раздел 14 -- Интеграции (Context Mapping).
Интеграции -- главный источник инцидентов в распределенной системе. Контекст "Заказы" взаимодействует с Каталогом (REST), Оплатой (REST), Складом (REST), Доставкой (Kafka) и Уведомлениями (Kafka).
Конфигурация подключений. URL, credentials, таймауты -- ConfigMap и Secrets в Kubernetes. Разные значения для dev / staging / prod. Таймауты обязательно задавать явно, а не полагаться на дефолты (бесконечное ожидание при зависании внешнего сервиса).
Circuit breaker dashboard. Resilience4j экспортирует метрики в Prometheus. Grafana-дашборд: состояние (CLOSED / OPEN / HALF_OPEN), процент ошибок, количество отклоненных вызовов. Алерт при переходе в OPEN.
Health checks. Endpoint /actuator/health проверяет доступность PostgreSQL, Redis, Kafka. Kubernetes использует его для liveness и readiness probes. Если PostgreSQL недоступен -- pod перезапускается (liveness). Если Kafka недоступен -- pod перестает получать трафик (readiness).
SLA-мониторинг. Grafana-дашборд с p50 / p95 / p99 latency для каждой интеграции. Алерт если p95 превышает SLA (например, > 300ms для Каталога). Отдельная панель для error rate.
Structured logging. Формат JSON с обязательными полями: integration_name, method, url, status_code, duration_ms, correlation_id. Позволяет быстро найти медленные или сбойные вызовы в Kibana / Loki.
6. Масштабирование
Источник: раздел 16 -- Нефункциональные требования.
NFR переводятся в конкретные инфраструктурные решения.
Производительность. Connection pool (HikariCP + PgBouncer), кэш (Redis с TTL 5 мин), JVM tuning (-Xms, -Xmx, GC). Capacity planning: сколько подов нужно для 50 rps на оформление заказа и 500 rps на каталог.
Доступность (99.9%). Минимум 2 реплики приложения. PostgreSQL failover через Patroni. Redis Sentinel для отказоустойчивости кэша. Kafka replication factor 3. Liveness/readiness probes в Kubernetes. Blue-green или rolling deployment для zero-downtime деплоя.
Масштабируемость (x5 при распродажах). HPA (Horizontal Pod Autoscaler) по CPU и custom metrics (requests per second). Rate limiting на API Gateway для защиты от перегрузки. Тестировать auto-scaling заранее, до распродажи, а не во время.
Хранение. Диски с запасом x3. Мониторинг disk usage (алерт > 80%). Партиционирование таблиц по дате для крупных объемов. Бекапы: ежедневный полный + WAL. Архивирование завершенных заказов старше 3 лет.
7. Мониторинг и алерты
Источник: раздел 16 -- Нефункциональные требования.
Сводная таблица метрик с порогами алертов. Каждая метрика -- повод для действия, не просто наблюдение.
| Метрика | Порог алерта | Инструмент | Действие при срабатывании |
|---|---|---|---|
| API p95 latency | > 200ms | Prometheus + Grafana | Проверить медленные запросы, нагрузку на БД, кэш |
| Error rate (5xx) | > 1% | Prometheus + PagerDuty | Проверить логи, состояние зависимостей |
| PostgreSQL connections | > 80% pool | pg_stat_activity | Проверить утечки соединений, увеличить пул |
| Kafka consumer lag | > 1000 msgs | Burrow / Kafka metrics | Проверить consumer, увеличить partitions |
| Disk usage | > 80% | node_exporter | Очистка, расширение, архивация |
| Pod restarts | > 3 за 10 мин | Kubernetes events | Проверить OOM, liveness probe, логи |
| Saga stuck | RUNNING > 10 мин | Custom metric | Проверить внешние системы, runbook |
| Circuit breaker OPEN | любой | Resilience4j metrics | Проверить внешнюю систему, SLA |
Стек наблюдаемости:
- Метрики: Prometheus (сбор) + Grafana (визуализация)
- Логи: ELK (Elasticsearch, Logstash, Kibana) или Loki + Grafana
- Трейсы: Jaeger с propagation через Kafka и REST
- Алертинг: PagerDuty или Alertmanager для критичных, Slack для warning