Недостатки микросервисной архитектуры
Микросервисная архитектура (MSA) — подход, когда система разбивается на небольшие независимые сервисы. У MSA есть недостатки, которые важно учитывать при проектировании.
1. Сложность управления распределёнными транзакциями
Проблема. В монолите транзакции управляются на уровне БД (ACID). В MSA данные распределены, и обеспечение согласованности требует сложных решений.
Пример: заказ оформлен, платёж прошёл, но товар не списался — пользователь заплатил за несуществующий товар.
Решения:
- Saga-паттерны: реализуют оркестрацию или хореографию транзакций с локальными шагами и компенсациями
- Outbox-паттерн: позволяет гарантировать отправку событий в шину сообщений после успешной локальной транзакции
2. Задержки из-за сетевых вызовов
Проблема. Межсервисные вызовы (HTTP, gRPC, AMQP) добавляют сетевые задержки, что может привести к ухудшению UX.
Пример: открытие страницы профиля пользователя требует вызовов к 10 сервисам — итого 1+ секунда задержки.
Практики:
- Кеширование на уровне API Gateway или Edge Cache
- Bulk- или фреймворк-запросы (например, GraphQL)
- Асинхронная обработка через сообщения и очереди
3. Оверхеды мониторинга и трассировки
Проблема. При десятках и сотнях сервисов сложно локализовать источник ошибки и собрать полную картину работы.
Пример: пользователь видит ошибку при оформлении заказа — неизвестно, виноват Cart, Orders или Payments.
Практики:
- Distributed Tracing (Jaeger, Zipkin, OpenTelemetry)
- Централизованные логи (ELK Stack, Loki)
- Метрики и алерты (Prometheus + Grafana)
4. Сложность тестирования и развёртывания
Проблема. Каждый сервис может иметь свою БД, конфигурацию и зависимости. Интеграционное тестирование всей системы требует поднятия множества сервисов.
Пример: тест Cart Service требует запуска Users, Products и Discounts — иначе тесты падают.
Практики:
- Контракты (Contract Testing): Pact, Spring Cloud Contract
- Mock-сервисы и виртуализация (WireMock, Hoverfly)
- Изолированные сценарии на уровне эндпоинтов
5. Дублирование данных и согласованность
Проблема. Каждый сервис хранит свою копию данных → возможны расхождения.
Пример: пользователь обновил email, но в Order History отображается старый адрес.
Практики:
- Event Sourcing и CQRS: разделяют чтение и запись и обеспечивают последовательность событий
- Change Data Capture (CDC): синхронизирует данные между БД через Kafka Connect или Debezium
6. Усложнение безопасности
Проблема. Требуется управлять аутентификацией и авторизацией в каждом сервисе, защищать межсервисный обмен данными.
Пример: забыли настроить проверку токена в одном из сервисов — появляется уязвимость.
Практики:
- API Gateway как точка авторизации
- OAuth2 / OpenID Connect, JWT-токены
- mTLS для коммуникации между сервисами
7. Проблемы проектирования границ сервисов
Проблема. Неправильное разбиение может привести к сильной связанности и усложнить сопровождение.
Пример: один сервис содержит и авторизацию, и профиль, и логи — изменить что-то без риска сложно.
Практики:
- Использовать Domain-Driven Design (DDD) и Bounded Contexts
- Анализировать частоту изменений: если два модуля часто меняются вместе — возможно, они должны быть одним сервисом
- Проводить ревью доменных моделей и пересматривать границы по мере роста системы
9. Проблемы с локальной разработкой
Проблема. Чтобы протестировать один сервис, нужно поднять зависимые сервисы (или их заглушки).
Пример: разработчик не может локально проверить Order Service без запуска Users и Payments.
Практики:
- Тестовые контуры (staging environment)
- Service Virtualization (например, WireMock для HTTP-заглушек)
- Local-режимы (например, Docker Compose для мини-стенда)
10. Версионирование API и обратная совместимость
Проблема. Изменение API одного сервиса может сломать другие.
Пример:
- v1:
GET /orders?user_id=123 - v2:
GET /orders?client_id=123→ Сервис аналитики ломается, т.к. ждётuser_id.
Практики:
- Semantic Versioning (SemVer) для API
- Deprecation Policy – явное уведомление об устаревании эндпоинтов
- API Gateway с маршрутизацией по версиям