Итак, в прошлых частях 1 и 2 я писал что обеспечение консистентности данных сильно мешает масштабированию. Что же делать на практике?
Здесь не будем касаться случаев ультра параллелизма и однонаправленных потоков данных вроде биржевых индикаторов по несколько миллионов событий в секунду, рассылаемые в реальном времени на сотни тысяч устройств. Разберем бизнес кейсы ближе к e-commerce, banking. Рассматриваем только data-bounded приложения, т.е. 90% случаев.
Я опущу длительные рассуждения (но могу рассказать в комментариях, если спросите) и представлю свою «поваренную книгу».
Также заранее извиняюсь за отсутствие конкретных кейсов, это сильно раздуло бы статью. Также предупреждаю, что при оформлении использовалась LLM, это упрощает форматирование, хотя некоторых может и раздражать. LLM проводилась также выверка терминов на соответствие многочисленным и размытым мнениям уважаемых авторов книг. Великоуважаемый Фаулер так и не смог дать внятного определения микросервисов.
ШАГИ
📌 1. Понять и измерить проблему в конкретном секторе
-
Определяем конкретную операцию или группу операций (например, оформление заказа, генерация отчётов, поиск товаров).
-
Измеряем текущие показатели: время отклика, пропускную способность, текущую нагрузку.
Это обязательно! Преждевременная оптимизация да еще в масштабах всего приложения — смертный грех архитектора!
📌 2. Устранять проблему в конкретном секторе
-
Не стараемся перепилить приложение целиком, это слишком дорого.
В сумме вырисовывается подход разделения на области высокой/полной консистентности (что затрудняет масштабирование) и области допустимой неполной / eventual consistency. В первом случае важна актуальность данных и отсутствие взаимных расхождений данных, упорядоченность данных и т.п. Во втором случае ценность актуальности или взаимной консистентности данных значительно ниже или уступает ценности оптимизации скорости в этой области.
Также можно нарисовать пути потоков данных, где важность времени ответа, это запрещает на пути разрезать БД и выносить в сеть взаимодействие.
Наложив области где типовые способы не справляются с повышением нагрузки на области и пути нежелательного разделения данных мы можем получить общее представление / визуальную карту по целесообразности и цене перехода на одну из распределенных архитектур.
Какие способы повышения масштабируемости следует рассмотреть и в каком порядке?
🟢 Дешёвые способы (простые, локальные оптимизации)
-
Оптимизация SQL-запросов и индексов
-
Кэширование (Redis, Memcached)
-
Простое горизонтальное масштабирование (реплики для чтения)
-
Простое шардирование (партиционирование таблиц в рамках одной БД)
Эти способы подробно описаны в 1-й части
🟡 Средние способы
Эти подходы требуют умеренных усилий и затрат, но при необходимости их можно относительно легко изменить или отменить:
-
Асинхронная обработка (очереди сообщений: Kafka, RabbitMQ)
-
Saga-паттерн (распределённые транзакции с компенсационными механизмами)
-
Средний способ, так как ввод компенсаций и отмены операции не сильно влияет на бизнес логику, ее не приходится переписывать полностью. Применяется, когда допустима eventual consistency с разумным временем рассогласованности данных и для бизнеса легко реализуемы обратные операции (отмена заказа к ним вряд-ли относится).
-
-
CQRS (особенно для аналитических и read-heavy сценариев):
-
Средний способ, так как CQRS для аналитики и чтения обычно прост и легко реализуем. Часто используется для разделения OLAP и OLTP задач. То есть этот паттерн легко просматривается исходя из назначения модуля.
-
-
Использование NoSQL-хранилищ (когда это не требует радикальной перестройки логики приложения):
-
Средний способ, если NoSQL-хранилище используется для простых задач (кэширование, хранение документов, логов, аналитических данных и т.д.), и не требует сложных транзакций и согласованности. Например, MongoDB для хранения документов, Elasticsearch для поиска, Cassandra для логов и аналитики — это средний уровень сложности.
-
🔴 Дорогие способы (сложные, труднообратимые, требуют значительных инвестиций и усилий)
Эти подходы применяются, когда средние способы исчерпаны, и требуют значительных изменений архитектуры и подходов к разработке:
-
Event Sourcing (как правило, сложный способ):
-
Дорогой способ, так как требует полной перестройки подхода к хранению данных и работы с ними.
-
Иногда (редко) может быть средним по сложности способом, если бизнес-процессы изначально событийно-ориентированы и уже изначально требуют такой подход. В большинстве случаев всё же Event Sourcing — это дорогой способ.
-
-
Полноценная микросервисная архитектура (с отдельными базами, инфраструктурой и сложной интеграцией)
-
Распределённые системы с географическим распределением и глобальной репликацией
-
Использование специализированных коммерческих решений (Oracle Exadata, SAP HANA, Google Spanner)
-
Сложные NoSQL-решения, когда они требуют радикального изменения логики приложения и подходов к согласованности:
-
Например, переход с реляционной БД на Cassandra для OLTP-транзакций с высокой нагрузкой и строгими требованиями к согласованности — это дорогое решение.
-
📌 Когда NoSQL относится к средним, а когда к дорогим решениям?
-
Средний способ:
NoSQL-хранилище используется для простых и понятных задач, например:
-
Аналитика и логи (Elasticsearch, ClickHouse)
-
Документы и JSON-данные (MongoDB)
-
Кэширование и простые структуры данных (Redis)
-
Event-логи и временные ряды (Cassandra, InfluxDB)
-
-
Дорогой способ:
NoSQL-хранилище используется для замены основной транзакционной базы данных, требуя радикального изменения логики приложения, например:
-
Переход с PostgreSQL на Cassandra для транзакций с высокой нагрузкой и сложными требованиями к согласованности и транзакционности.
-
Использование NoSQL в сценариях, где изначально была строгая транзакционная логика (банки, финансы, ERP-системы), и теперь приходится полностью перестраивать приложение.
-
📌 Пара слов про event sourcing
Event sourcing соперничает за 1 место по сложности с микросервисами. Его применение ограничено узкими бизнес областями.
Если ваш бизнес-домен уже событийно-ориентированный (например, банковские транзакции, учётные системы, системы аудита и бухгалтерии):
-
В таких случаях ES может оказаться естественным и логичным подходом.
-
Дополнительные затраты на проектирование и реализацию окупаются прозрачностью и гибкостью системы.
Также к серьезным минусам паттерна относится невозможность эволюционного перехода с простых паттернов, требуется переписать весь код, в отличие от эволюционных возможностей микросервисов. Поэтому Event Sourcing имеет смыл только если требуется аудит, реплей и прозрачность истории.
🎯 Итого:
|
Категория |
Что входит |
|---|---|
|
🟢 Дешёвые способы |
SQL-оптимизация, кэширование, простое шардирование, реплики для чтения |
|
🟡 Средние способы |
Асинхронность (Kafka/RabbitMQ), Saga-паттерн (компенсации), CQRS (особенно аналитика), отдельные БД, NoSQL (для простых и понятных сценариев) |
|
🔴 Дорогие способы |
Event Sourcing (обычно), микросервисы, сложные распределённые системы, сложные NoSQL-решения, коммерческие специализированные решения |
📌 Что чаще всего отделяем от монолита (от общей БД)?
«Гонялки данных» — сервисы, которые:
-
✅ Не находятся на критическом пути бизнес-процессов (то есть, их временная недоступность или задержки не парализуют основной бизнес).
-
✅ Не требуют строгой консистентности и актуальности данных (могут работать с данными, которые слегка устарели, eventual consistency).
-
✅ Часто имеют ad-hoc характер (аналитика, отчёты, уведомления, интеграции с внешними системами и т.п.).
Такие сервисы действительно можно выделять в отдельные микросервисы, потому что их проблемы (сетевые задержки, временные сбои, eventual consistency) не повлияют критически на основной бизнес.
📌 Примеры таких «не критичных» микросервисов:
-
🔹 Сервисы аналитики и отчётности
Например, сервис, собирающий статистику, формирующий отчёты и BI-дашборды. Если он временно недоступен, основной бизнес-поток не пострадает.
-
🔹 Сервисы отправки уведомлений (email, push, SMS)
Если уведомления задерживаются на несколько секунд или минут, это не критично для основной бизнес-логики.
-
🔹 Сервисы интеграции с внешними системами
Например, выгрузка данных во внешние CRM, ERP, маркетинговые платформы. Если данные попадут туда чуть позже, это также не критично.
-
🔹 Сервисы аудита и логирования
Сбор логов, аудит действий пользователей, мониторинг. Их временная недоступность не влияет на основной бизнес.
-
🔹 Сервисы рекомендаций, персонализации и ML
Если сервис персонализации временно недоступен, пользователи просто получат стандартный контент без персонализации.
Под катом рисуночки для визуалов
Ниже представлены 5 архитектурных схем, которые действительно покрывают практически все (99.9%) типовые сценарии приложений. Эти схемы идут от простых (для большинства приложений) к сложным (для нагруженных, распределённых и сложных систем).
🚩 1. Монолит с единой БД (простая CRUD-система)
Подходит для:
-
Малых и средних проектов
-
Простых бизнес-приложений (админки, блоги, небольшие интернет-магазины)
Архитектурная схема:
+---------------------------+ | Монолитное приложение | | (бизнес-логика, UI, API) | +-------------+-------------+ | v +------------------+ | Одна база данных | +------------------+
🚩 2. Монолит с Read-only репликами и кэшированием
Подходит для:
-
Средних приложений с умеренной нагрузкой на чтение
-
Большинства веб-приложений и интернет-магазинов среднего размера
Архитектурная схема:
+------------------------------+ | Монолитное приложение | | (бизнес-логика, UI, API) | +--------------+---------------+ | v +--------------------+ | Основная база (RW) +------+ +--------------------+ | v (асинхронная репликация) +-------------------------+ | Read-only реплики (RO) | +------------+------------+ | v +-------------------+ | Кэш (Redis и т.п.)| +-------------------+
🚩 3. Монолит (или модульный монолит) с асинхронными проекциями (CQRS-lite)
Подходит для:
-
Большинства приложений с умеренной или высокой нагрузкой на чтение
-
Систем с отчётами, аналитикой, поиском
Архитектурная схема:
+------------------------------+ | Монолитное ядро | | (бизнес-логика, API команд) | +--------------+---------------+ | v (события через брокер) +--------------------+ | Брокер сообщений | | (Kafka, RabbitMQ) | +---------+----------+ | +--------+--------+--------+ v v v +--------------+ +--------------+ +------------------+ | Read-only UI | | Аналитика | | Полнотекстовый | | проекция | | и отчёты | | поиск (Elastic) | +--------------+ +--------------+ +------------------+
🚩 4. Микросервисная архитектура с отдельными БД и eventual consistency
Подходит для:
-
Крупных приложений с высокой нагрузкой
-
Систем с независимыми командами разработки и разными доменами
Архитектурная схема:
+-------------+ +-------------+ +-------------+ | Микросервис | | Микросервис | | Микросервис | | Заказы | | Платежи | | Склад | +------+------+ +------+------+ +------+------+ | | | v v v +-------------+ +-------------+ +-------------+ | БД Заказов | | БД Платежей | | БД Склада | +-------------+ +-------------+ +-------------+ | | | +----------+-----------+-----------+----------+ | | v v +---------------+ +------------------+ | Брокер сообщений (Kafka, RabbitMQ и т.п.)| +---------------+-------+------------------+ | +----------+----------+ v v +--------------+ +-----------------+ | Аналитика | | Read-only UI | | и отчёты | | проекции | +--------------+ +-----------------+
🚩 5. Event Sourcing + CQRS (для сложных систем с высокими требованиями к аудиту и истории)
Подходит для:
-
Финансовых систем, бухгалтерии
-
Систем с высоким требованием к аудиту и восстановлению состояния на любой момент времени
-
Высоконагруженных распределённых приложений с миллионами событий
Архитектурная схема:
+-------------------+ команды +------------------+ | +----------------->| | | Клиенты (UI/API)| | Command Handler | | |<-----------------+ | +---------+---------+ ответы +--------+---------+ ^ | | события (через брокер) v +---------+---------+ +-------------------+ | Read-only модели |<----------------| Event Store (лог) | | (проекции) | события +-------------------+ +---------+---------+ | v +-------------------+ | Аналитика, отчёты | +-------------------+
📌 Итоговая таблица выбора архитектуры:
|
Архитектура |
Сложность |
Нагрузка |
Сложность логики |
Команды разработки |
|---|---|---|---|---|
|
Монолит + одна БД |
Низкая |
Низкая |
Простая |
1 небольшая |
|
Монолит + реплики и кеш |
Средняя |
Средняя |
Средняя |
1 небольшая |
|
Монолит + CQRS-lite (проекции) |
Средняя |
Средняя-Высокая |
Средняя |
1-2 небольшие |
|
Микросервисы (отдельные БД) |
Высокая |
Высокая |
Высокая |
Несколько команд |
|
Event Sourcing + CQRS |
Очень высокая |
Очень высокая |
Очень высокая |
Несколько команд |
🚩 Итоговый вывод:
Эти 5 схем покрывают практически все возможные сценарии (99.9%) разработки приложений:
-
Монолит + одна БД — 50-60% приложений (простые CRUD)
-
Монолит + реплики и кеш — 20-30% приложений (средние нагрузки)
-
Монолит + CQRS-lite (асинхронные проекции) — 5-10% приложений (аналитика, сложные UI)
-
Микросервисы с отдельными БД — 3-5% приложений (крупные распределённые системы)
-
Event Sourcing + CQRS — около 1% приложений (финансовые, бухгалтерские, высоконагруженные системы с аудитом)
Замечу, что вероятности программисту попасть в конкретный тиа проекта совсем другие. Нужно учесть что 4-5 уровни сложности (если они обоснованы) применяются в крупных проектах и вероятность программисту попасть на 4-5 уровень близка к 20-30%
Таким образом, эти схемы закрывают практически все потребности, которые могут возникнуть в реальных проектах.
Напомню, что рассматриваются только усилия по повышению масштабируемости в системах массового обслуживания, data-bounded. Впрочем, это весьма распространенный класс задач. Иные архитектурные качества не рассматриваются: и с одним то качеством не сразу разберешься.
На этом серия статей по архитектурным паттернам заканчивается. В 1-ю часть я внес несколько добавлений по event sourcing.
Удачной архитектуры!
Дальше, видимо, будет серия по архитектурным паттернам борьбы со сложностью в больших проектах
ссылка на оригинал статьи https://habr.com/ru/articles/900302/
Добавить комментарий