DDD-спецификация: гайд для DevOps-инженера

DevOps-гайд по DDD-спецификации: подготовка PostgreSQL и Kafka, deploy в Kubernetes, мониторинг агрегатов и Saga, плейбуки на инциденты.

DDD DevOps

DDD DevOps: введение

DDD DevOps — devOps-инженер участвует в 6 из 16 разделов DDD-спецификации. Его задача -- обеспечить развертывание, эксплуатацию и наблюдаемость системы, спроектированной по DDD.

Разделы, содержащие DevOps-блоки:

РазделТемаФокус DevOps
1Bounded ContextРазвертывание, сетевые связи, секреты
3.4Схема базы данныхPostgreSQL, миграции, бекапы, мониторинг БД
8Domain EventsKafka, Outbox, DLQ, Schema Registry
12Saga / 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> 200msPrometheus + GrafanaПроверить медленные запросы, нагрузку на БД, кэш
Error rate (5xx)> 1%Prometheus + PagerDutyПроверить логи, состояние зависимостей
PostgreSQL connections> 80% poolpg_stat_activityПроверить утечки соединений, увеличить пул
Kafka consumer lag> 1000 msgsBurrow / Kafka metricsПроверить consumer, увеличить partitions
Disk usage> 80%node_exporterОчистка, расширение, архивация
Pod restarts> 3 за 10 минKubernetes eventsПроверить OOM, liveness probe, логи
Saga stuckRUNNING > 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