Как стать автором
Обновить

Архитектурные паттерны для высокой масштабируемости. Часть 3

Уровень сложностиСредний
Время на прочтение9 мин
Количество просмотров8K

Итак, в прошлых частях 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%) разработки приложений:

  1. Монолит + одна БД — 50-60% приложений (простые CRUD)

  2. Монолит + реплики и кеш — 20-30% приложений (средние нагрузки)

  3. Монолит + CQRS-lite (асинхронные проекции) — 5-10% приложений (аналитика, сложные UI)

  4. Микросервисы с отдельными БД — 3-5% приложений (крупные распределённые системы)

  5. Event Sourcing + CQRS — около 1% приложений (финансовые, бухгалтерские, высоконагруженные системы с аудитом)

Замечу, что вероятности программисту попасть в конкретный тиа проекта совсем другие. Нужно учесть что 4-5 уровни сложности (если они обоснованы) применяются в крупных проектах и вероятность программисту попасть на 4-5 уровень близка к 20-30%

Таким образом, эти схемы закрывают практически все потребности, которые могут возникнуть в реальных проектах.

Напомню, что рассматриваются только усилия по повышению масштабируемости в системах массового обслуживания, data-bounded. Впрочем, это весьма распространенный класс задач. Иные архитектурные качества не рассматриваются: и с одним то качеством не сразу разберешься.

На этом серия статей по архитектурным паттернам заканчивается. В 1-ю часть я внес несколько добавлений по event sourcing.

Удачной архитектуры!

Дальше, видимо, будет серия по архитектурным паттернам борьбы со сложностью в больших проектах

Теги:
Хабы:
+6
Комментарии11

Публикации

Истории

Работа

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
14 мая
LinkMeetup
Москва
5 июня
Конференция TechRec AI&HR 2025
МоскваОнлайн
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область