1. Предисловие
Шаблоны такие шаблонные:
-
Я часто встречаю шаблонное предложение даже для слабо нагруженных систем "всё разбить на домены, все домены выделить в микросервисы и это решит все проблемы". Особенно часто пытаются так делать архитекторы-новички, необоснованно используя популярный шаблон и не пытаясь применить решения, более подходящие масштабу и типу задачи.
Какие недостатки имеет такой подход:
-
Сложность разработки.
Вместо одной монолитной системы вы создаете множество небольших сервисов, каждый из которых нужно проектировать, разрабатывать, тестировать и разворачивать отдельно.
Появляется необходимость в четком определении границ ответственности (bounded contexts), что требует глубокого анализа бизнеса. Если границы изменяются, то микросервисы очень сложно переделать.
-
Усложнение инфраструктуры.
Для управления микросервисами требуется развитая инфраструктура: оркестрация контейнеров (например, Kubernetes), системы мониторинга (Prometheus, Grafana), централизованное логирование (ELK-стек или аналог), сервисы API Gateway и балансировки нагрузки.
Увеличивается количество сетевых взаимодействий, что повышает вероятность сбоев и требует обработки сложных сценариев (например, таймауты, повторные запросы, частичные сбои).
-
Высокие требования к DevOps и сложности в поддержке.
Чтобы микросервисы работали стабильно, нужны автоматизация CI/CD, управление версиями, мониторинг, контейнеризация (Docker и т. д.), а также устойчивость к отказам.
Поломка одного микросервиса может привести к цепной реакции, если зависимые сервисы не умеют корректно обрабатывать ошибки.
Трудно отслеживать и исправлять баги в распределенной системе, особенно без инструментов трассировки (например, Jaeger, OpenTelemetry)
-
Проблемы с производительностью.
Высокие сетевые задержки
Сериализация/десериализация данных (например, JSON, Protobuf) также добавляет накладные расходы
-
Безопасность.
Микросервисы увеличивают количество точек входа для потенциальных атак, поскольку каждый сервис может иметь собственные уязвимости и требует отдельной защиты.
Сложность управления доступом и аутентификации между сервисами
Вот сколько недостатков!
В статье придется ограничиться только вопросами масштабирования, быстродействия и времени ответа.
Что ж, проверим, знаете ли вы другие способы масштабирования информационных систем. Попробуем начать с других, более легких подходов. К сложным решениям мы придем тогда, когда более простые подходы к масштабированию (например, шардирование или кэширование) уже исчерпали свои возможности.
-
Многабукф, разбор частных случаев убрал под кат.
Что бы я ожидал от архитектора на примере магазина уровня М-Видео
Архитектурное решение для онлайн-магазина
При среднем масштабе нагрузки оправдан комбинированный подход, при котором основные домены критичные к времени сетевого отклика и к надежности сети (Каталог, Склад, Пользователи, Уведомления) остаются внутри монолита с возможностью запуска нескольких экземпляров для балансировки нагрузки. А критичные по производительности (Заказы, Аналитика) и критичные к безопасности задачи (Платежи) вынесены в отдельные микросервисы.
Разделение доменных областей и баз данных
Домен |
Решение |
База Данных |
---|---|---|
Каталог товаров |
Модуль в монолите |
Общая БД с Складом |
Заказы |
Выделенный микросервис |
Отдельная БД |
Платежи |
Выделенный микросервис |
Отдельная БД |
Склад |
Модуль в монолите |
Общая БД c Каталогом |
Пользователи |
Модуль в монолите (без репликации) |
Общая БД с Уведомлениями |
Уведомления |
Воркеры в монолите |
Общая БД с Пользователями |
Аналитика |
Выделенный микросервис или модуль в монолите |
Отдельная БД (например, специализированная аналитическая), CQRS |
Ключевые особенности архитектуры
-
Два экземпляра Монолита и Балансировщик
Повышение отказоустойчивости и распределение нагрузки.
Лёгкое горизонтальное масштабирование при росте трафика.
-
Выделенные Микросервисы (Заказы, Платежи, Аналитика)
Независимое развитие, масштабирование по горизонтали.
Снижение нагрузки на монолит, упрощение соблюдения норм безопасности для платежей.
-
Отсутствие Репликации для Пользователей
Упрощает архитектуру при невысокой нагрузке на этот домен.
Достаточно одного экземпляра базы для сохранения профилей и аутентификации.
-
Уведомления во Внутренних Воркерах
Асинхронная модель обработки событий снижает задержки и повышает отказоустойчивость.
Меньше сетевых overhead при доступе к профилям пользователей.
-
Отдельная Аналитическая БД
Позволяет эффективно обрабатывать большие объёмы исторических данных, формировать метрики и отчёты.
Отделение от основных транзакционных баз улучшает общую производительность системы.
Вывод
Данная архитектура сочетает простоту управления монолитными модулями (Каталог, Склад, Пользователи, Уведомления) и выигрышные аспекты микросервисного подхода (Заказы, Платежи, Аналитика). Горизонтальное масштабирование достигается запуском нескольких экземпляров монолита и выделением микросервисов с независимыми базами. Такой подход обеспечивает высокую производительность, надёжность и удобство сопровождения онлайн-магазина.
Немножко рефлексии и обоснования выбора
Да, я бы ждал от архитектора такого решения. А не просто разрезать все домены на микросервисы. Можно выделить ключевые принципы такого подхода:
Доводы для отрезания домена
требования к безопасности (платежи)
масштабирование бизнес-логики (не СУБД) выше чем позволяет вертикальное масштабирование и несколько серверов для инстансов монолита, то есть от 200-500 vCPU, но
вам это не нужноэтот фактор переоценен и решает только для систем очень большого масштаба
Доводы против отрезания домена
важна низкая задержка при взаимодействии между доменами
имеется большой поток данных между доменами
высокая стоимость разработки, сопровождения
проблемы при изменении границ домена, особенно в начале жизненного цикла системы, когда бизнес процессы еще не сложились
Ускоряем монолит
кеширование, шардирование и репликация БД
CQRS
no ACID
Плохие подходы:
❌ "Давайте сделаем всё микросервисами, это же модно"
❌ "Разделим по доменам, а там разберемся"
❌ "Начнем резать, а транзакции потом как-нибудь решим"
Хороший подход:
✅ Сначала анализ данных и транзакций
✅ Затем группировка по критичным связям
✅ И только потом решение об отделении сервисов
Масштаб побольше и проблемы побольше
Для масштаба интернет магазина как "Пятерочка-доставка" архитектура должна быть существенно сложнее. Тут практика складывается за распределенными решениями, в частности за микросервисами:
-
Домен: Каталог товаров
Разделение на поддомены:
Основной каталог (товары, категории)
Ценообразование (цены, акции, скидки)
Контент-менеджмент (описания, фото) БД:
Отдельная БД для каждого поддомена
Репликация read-only копий
Redis для кэширования
ElasticSearch для поиска
-
Домен: Заказы
Разделение на поддомены:
Онлайн-заказы
Кассовые операции
Возвраты
История заказов БД:
Шардированная БД по регионам
Архивная БД для истории
Очереди для обработки
-
Домен: Платежи
Разделение на поддомены:
Онлайн-платежи
Кассовые платежи
Корпоративные расчеты
Бухгалтерия БД:
Отдельные БД для каждого типа платежей
Специализированная БД для бухгалтерии
-
Домен: Склад
Разделение на поддомены:
Центральный склад
Региональные склады
Магазины
Логистика БД:
Отдельные БД для каждого региона
Time-series БД для движения товаров
Graph БД для логистической оптимизации
-
Домен: Пользователи
Разделение на поддомены:
Клиенты
Сотрудники
Программа лояльности
Права доступа БД:
Географически распределенная БД клиентов
Отдельная защищенная БД сотрудников
БД программы лояльности
-
Домен: Уведомления
Разделение на поддомены:
Клиентские уведомления
Внутренние коммуникации
Маркетинговые рассылки БД:
Queue-oriented storage
Архив коммуникаций
-
Домен: Аналитика
Разделение на поддомены:
Операционная аналитика
Финансовая аналитика
Маркетинговая аналитика
Прогнозирование БД:
Data Warehouse
OLAP кубы
Data Lake
Новые домены:
Поставщики (отдельная БД)
Маркетинг и акции (отдельная БД)
Производство (для собственных торговых марок)
Качество и сертификация
Итого около 20-25 баз данных, сгруппированных по:
Функциональному назначению
Географическому признаку
Требованиям к производительности
Требованиям к безопасности
Особенности:
Географическое шардирование
Мульти-датацентр развертывание
Различные типы БД под разные задачи
Сложная система репликации
Отказоустойчивые кластеры
Системы мониторинга и алертинга
Отдельные среды разработки/тестирования
Дополнительные направления, которые я не учел:
Разработка кассового ПО
Системы видеонаблюдения и безопасности
Системы управления персоналом
Системы планирования ресурсов
Мобильные приложения для разных брендов
Системы автоматизации складов
Системы прогнозирования спроса
Системы контроля качества
Системы управления транспортом
Системы электронного документооборота
IoT решения (холодильники, датчики и т.д.)
Системы энергоэффективности
Эволюция архитектуры по мере роста масштаба
Давайте рассмотрим пример, чтобы оценить потенциальные издержки и преимущества эволюционного подхода с последующим разделением базы данных (БД) по доменам.
Начальные условия
Текущая нагрузка: 500 запросов в секунду (QPS) на чтение, 100 QPS на запись.
Ожидаемый рост нагрузки: 20% в месяц.
Текущая база данных: монолитная, с репликацией для чтения.
Операционные затраты на поддержку монолитной БД: 10 часов в неделю.
Эволюционный подход
Шаг 1: Репликация и шардирование (временная экономия 3–6 месяцев)
Репликация: уменьшаем нагрузку на основную БД на 30% (чтение).
Шардирование: уменьшаем нагрузку на основную БД на 20% (запись).
Операционные затраты: +20% (добавляем управление репликацией и шардированием).
Шаг 2: Разделение БД по доменам (через 6–12 месяцев)
Разделение: создаем отдельные БД для каталога, заказов и корзины.
Масштабируемость: каждый домен можно масштабировать независимо.
Операционные затраты: +50% (добавляем управление несколькими БД).
Издержки и преимущества
Издержки
Избыточная работа: при разделении БД по доменам часть работы по настройке репликации и шардирования может оказаться избыточной.
Сложности миграции: потребуется мигрировать данные из монолитной БД в отдельные БД по доменам.
Преимущества
Быстрая оптимизация: репликация и шардирование быстро улучшают производительность.
Гибкость: разделение БД по доменам позволяет масштабировать каждый домен независимо.
Улучшенная поддержка: операционные затраты на поддержку отдельных БД могут быть ниже, чем на поддержку монолитной БД.
Цифровое сравнение
Сценарий |
Нагрузка (QPS) |
Операцион-ные затраты (часов/неделю) |
Издержки |
Преиму-щества |
---|---|---|---|---|
Монолитная бизнес логика и данные |
500 (чтение), 100 (запись) |
10 |
- |
- |
Репликация + шардирование |
350 (чтение), 80 (запись) |
12 |
Избыточная работа |
Быстрая оптимизация |
Разделение БД по доменам |
200 (чтение), 50 (запись) |
15 |
Сложности миграции |
Гибкость, улучшенная поддержка |
Выводы
Переход на сложные паттерны одним скачком приводят к большим рискам и длительным срокам до появления первых результатов.
Эволюционный подход с последующим разделением БД по доменам может привести к избыточной работе и сложностям миграции. Однако, он также позволяет быстро оптимизировать производительность и обеспечивает гибкость и улучшенную поддержку в долгосрочной перспективе.
Чтобы минимизировать издержки, рекомендуется:
Планировать архитектуру: заранее продумать структуру БД и потенциальные точки роста.
Автоматизировать процессы: использовать инструменты для автоматизации управления БД и миграции данных.
Мониторить производительность: регулярно отслеживать нагрузку и производительность, чтобы корректировать архитектуру при необходимости.
TLDR: до применения такого тяжелого и полного недостатков инструмента как микросервисы я бы предложил сначала использовать возможности оптимизации с более легкими инструментами, и лишь дойдя до предела их возможностей рассмотреть использование микросервисов. И то, не всегда!
Вот эти инструменты:
Шардирование
Репликация
Кеширование
CQRS
Event sourcing
Ослабление требований ACID
Довольно трудно понять, какой инструмент применять первым и достаточно ли его для требуемого уровня быстродействия. Чтобы понять это погрузимся немного в теорию.
2. Распространение данных по распределенной системе
Попробуем найти общее во всех этих методах повышения производительности, включая микросервисы.
Распространение данных по распределенной системе требует времени из-за медленной сети. Если требуется консистентность данных во всей системе то нужно ждать пока данные полностью распространятся по ней. Очевидные способы борьбы за скорость в распределенной архитектуре
не требовать одновременной консистентности во всей системе (event sourcing, cqrs, no acid)
требовать консистентности данных, но лишь в ограниченных областях системы (bounded context, например в микросервисах) и ограничить распространение данных за их пределы (только по API и т.д.)
не блокировать данные в ожидании консистентности и проверять их уже после изменений с возможностью обратных действий (паттерн сага)
отказ от распределенной архитектуры или объединение неудачно разделенных микросервисов
По существу, все архитектурные паттерны выигрывают в быстродействии за счет допущения неполной консистентности данных. И это основной trade-off.
В монолитной системе для повышения скорости мы можем отказаться от длительных блокировок данных, что также приводит к потере согласованности.
Если четко определить требования бизнеса к согласованности данных, то это развяжет нам руки в применении приёмов повышения быстродействия и масштабирования.
3. Шаблоны data-bounded масштабирования
Шардирование (sharding)
Смысл шардирования и как оно повышает производительность
Шардирование — это метод разделения данных на независимые части (шарды), которые хранятся на разных серверах. Это помогает распределить нагрузку, ускорить запросы и избежать узких мест.
Примеры
Шардирование по пользователю
Данные изолируются по идентификатору пользователя (например, user_id
).
Какие данные изолируются: профиль, заказы, сообщения.
Как повышает производительность: равномерное распределение нагрузки между шардами, уменьшение объема данных на каждом сервере, параллельная обработка запросов.
Пример: Социальная сеть, где данные каждого пользователя хранятся отдельно.
Шардирование по типу данных
Данные разделяются по их назначению (например, заказы в одном шарде, инвентарь — в другом). Но бизнес-логика еще может работать в монолите
Какие данные изолируются: заказы, товары, остатки.
Как повышает производительность: уменьшение конкуренции за ресурсы, оптимизация запросов, настройка баз под конкретные задачи.
Пример: Интернет-магазин, где операции с заказами и инвентарем не конфликтуют.
Шардирование по времени
Данные изолируются по временным интервалам (например, логи по месяцам).
Какие данные изолируются: журналы, метрики, архивы.
Как повышает производительность: свежие данные обрабатываются быстрее, старые шарды можно архивировать, запросы работают с меньшими объемами данных.
Пример: Система логирования, где запросы обычно касаются недавних событий.
Как это работает в общем случае
Шардирование снижает нагрузку на отдельные сервера за счет:
Увеличения параллелизма.
Ускорения запросов за счет работы с меньшими объемами данных.
Когда использовать: когда данных слишком много для одного сервера или нагрузка слишком высока.
CQRS
CQRS — это архитектурный паттерн, который разделяет:
-
Команды (Commands) — операции изменения состояния (например, добавление товара в корзину, перевод денег).
Ответственность: Модификация данных.
Модель данных: Оптимизирована для записи.
-
Запросы (Queries) — операции чтения (например, получение списка товаров, отображение баланса).
Ответственность: Извлечение данных.
Модель данных: Оптимизирована для чтения.
Основная идея CQRS: разделить модель для чтения и записи, чтобы каждая часть могла быть максимально эффективной для своей задачи.
Trade-off: мы жертвуем консистентностью данных, создавая еще одну базу редко изменяемых и, возможно, уже устаревших данных Мы перекидываем нагрузку на чтение на новую БД там, где высокая актуальность не требуется. Например, паттерн активно используется для аналитических систем где устаревание данных на несколько минут или часов некритично.
Event sourcing
Вместо хранения текущего состояния объекта, сохраняются все его изменения в виде последовательности событий. Раз мы не храним данные, то мы можем не заботиться об их консистентности и не ждать пока эти данные распространятся и станут одинаковыми во всей системе. Ну а если понадобится узнать состояние, то мы восстановим его по запросу в любой момент времени.
Trade-off: мы жертвуем консистентностью данных состояния, его не храним совсем, но можем узнать/вычислить состояние когда это понадобится.
Event Sourcing особенно эффективен в сценариях, где:
Чтение текущего состояния происходит реже чем запись (например, логирование)
Важна возможность восстановить состояние системы (например, платежная подсистема)
Event sourcing + CQRS
Как они работают совместно?
-
Часть записи (Commands):
События (events) записываются в журнал событий (event store) как результат обработки команд (например, "Добавить товар в корзину").
Текущее состояние системы (например, корзина) не обновляется напрямую. Вместо этого всё состояние можно восстановить из последовательности событий.
-
Часть чтения (Queries):
Для быстрого чтения (например, отображения корзины) используются проекции.
Проекции (read models) строятся асинхронно на основе событий, записанных в event store.
Эти проекции представляют агрегированное или предварительно вычисленное состояние, оптимизированное для запросов.
Кэширование
Кэширование — это метод временного хранения данных в быстром доступе (например, в оперативной памяти) для ускорения работы системы. Оно снижает нагрузку на базу данных и ускоряет обработку повторяющихся запросов.
Где используется кэширование
-
На стороне приложения. Локальный кэш в памяти для хранения часто запрашиваемых данных.
Пример: Кэширование профиля пользователя или настроек.
-
На уровне базы данных. Инструменты вроде Redis или Memcached хранят результаты запросов, чтобы избежать повторных обращений к медленной БД.
Пример: Список популярных товаров в интернет-магазине.
-
На уровне сети. CDN (Content Delivery Network) кэширует статический контент (изображения, видео) близко к пользователю.
Пример: Быстрая загрузка веб-страниц.
Как повышает производительность
Ускоряет доступ к данным. Позволяет обращаться к кэшу вместо медленных операций чтения из базы.
Снижает нагрузку на сервер. Уменьшает количество запросов к БД или API.
Улучшает масштабируемость. Повторяющиеся запросы обрабатываются быстрее, освобождая ресурсы для новых операций.
Проблемы
Согласованность данных: Обеспечение однородности данных на всех узлах.
Сетевые задержки и разделение: Задержки или сбои в сети могут препятствовать своевременной инвалидации.
Масштабируемость: Координация инвалидации при большом числе узлов усложняется.
Надёжность: Гарантия доставки сообщений об инвалидации даже при отказах.
Оверхед на коммуникацию: Частые обновления приводят к повышенному сетевому трафику.
Стратегии инвалидации кеша
Time-to-Live (TTL): Кеш автоматически истекает через заданное время. Просто, но возможны устаревшие данные.
Явная инвалидация: При изменении данных отправляются уведомления для очистки кеша. Точный, но требует надёжной доставки.
-
Write-through/Write-back:
Write-through: Синхронная запись в кеш и хранилище.
Write-back: Асинхронная запись из кеша в хранилище.
Версионность: Использование версий данных для проверки актуальности кеша.
Pub/Sub Модель: Узлы подписываются на события изменений и получают уведомления.
Локальная и глобальная инвалидация: Комбинация локальных очисток и глобальных обновлений.
Самоинвалидация кеша: Кеш самостоятельно отслеживает изменения и обновляется.
Когда использовать
Данные часто запрашиваются, но редко изменяются (например, справочники, профили пользователей).
Результаты запросов требуют сложных вычислений или их выполнение занимает много времени.
Необходима минимизация задержек для пользователей (например, в высоконагруженных системах).
Ослабление требований к ACID / no ACID
ACID (атомарность, согласованность, изолированность, устойчивость) гарантирует надежность транзакций в базах данных. Однако в распределенных системах соблюдение всех этих требований зачастую снижает производительность и масштабируемость.
Ослабление ACID позволяет ускорить работу системы, жертвуя строгой согласованностью данных в пользу eventual consistency.
Автор теоремы CAP использует акроним BASE для описания не совсем ACID систем
Basically Available
Soft state
Eventual consistency
Варианты отказа от части ACID для обеспечения скорости
-
Consistency (согласованность):
Заменяется на eventual consistency, где данные становятся согласованными со временем.
Пример: В распределенных базах данных (DynamoDB, Cassandra) данные между репликами синхронизируются асинхронно.
-
Isolation (изоляция):
Ослабление изоляции позволяет выполнять транзакции параллельно, даже если они временно конфликтуют.
Пример: Использование уровней изоляции "Read Committed" или "Read Uncommitted".
-
Durability (устойчивость):
Ослабление гарантии устойчивости позволяет временно хранить транзакции в памяти перед записью на диск, что ускоряет операции.
Пример: Redis допускает потерю данных при сбое.
No ACID могут быть и традиционные RDBMS системы в определенных сценариях
Примеры "no-ACID" транзакций в PostgreSQL для ускорения работы
PostgreSQL, будучи реляционной СУБД, по умолчанию стремится к соблюдению ACID. Однако, существуют способы ослабить некоторые свойства для повышения производительности в определенных сценариях:
-
UNLOGGED
таблицы:Создание таблиц с ключевым словом
UNLOGGED
отключает запись изменений в WAL (Write-Ahead Log). Это значительно ускоряет операции записи, так как не требуется накладных расходов на журналирование.Ослабление: Durability. В случае сбоя сервера данные в
UNLOGGED
таблицах будут потеряны.Пример: Временные таблицы для промежуточных результатов вычислений, таблицы для хранения кэша, который можно легко восстановить.
-
Асинхронная фиксация (
synchronous_commit = off
илиlocal
):По умолчанию PostgreSQL ожидает записи WAL на диск перед подтверждением транзакции (синхронная фиксация). Установка
synchronous_commit
вoff
илиlocal
позволяет серверу подтверждать транзакции до фактической записи на диск.Ослабление: Durability. При сбое сервера между подтверждением транзакции и записью WAL на диск, данные могут быть потеряны.
local
гарантирует запись в локальный WAL, но не на все реплики в случае репликации.Пример: Массовая загрузка данных, где небольшая вероятность потери данных допустима в обмен на значительное ускорение.
-
Уровень изоляции
READ UNCOMMITTED
:Позволяет транзакции видеть незафиксированные изменения других транзакций ("грязное чтение").
Ослабление: Isolation. Может привести к чтению несогласованных данных.
Пример: Ситуации, где скорость чтения критически важна, а "грязное чтение" не приводит к серьезным проблемам, например, приблизительный подсчет количества записей.
Когда использовать
Высоконагруженные распределенные системы (NoSQL и SQL базы данных).
Сценарии, где скорость важнее строгой согласованности (социальные сети, системы аналитики).
Итог: Ослабление ACID — это компромисс между производительностью и строгими гарантиями консистентности.
Data Denormalization
Нарушение нормальных форм для уменьшения количества соединений (JOIN) в запросах, что может значительно повысить скорость выполнения запросов за счет увеличения объема данных.
В следующей серии (будет опубликовано 12.01.2025 11:00):
Последний из data-bounded шаблонов масштабирования: микросервисы
О природе ограничений data-bounded масштабируемости. Осторожно, матан!
Шаблоны CPU-bounded масштабирования
Практические выводы
Комментарии (31)
Aceki
11.01.2025 18:13Здравствуйте. Какие книги можете порекомендовать для начинающих архитекторов?
Dhwtj Автор
11.01.2025 18:13Ле Корбюзье ))
По решению проблем роста стоимости разработки для крупных систем:
Роберт Мартин — «Чистая архитектура» (Clean Architecture)
Вон Вернон — «Реализация предметно-ориентированного проектирования» (Implementing Domain-Driven Design)
Мартин Фаулер — «Рефакторинг. Улучшение существующего кода» (Refactoring: Improving the Design of Existing Code)
Инженерия требований
Карл Вигерс, Джой Битти — «Разработка требований к программному обеспечению» (Software Requirements)
Организация работы команды и роли архитектора
Гарт Форд, Мартин Фаулер — «Руководство по техническому лидерству» (The Tech Lead Handbook)
О том, как архитектору и техническому лидеру эффективно взаимодействовать с командой.
Вдохновение и философия
Фредерик Брукс — «Мифический человеко-месяц» (The Mythical Man-Month)
Классика управления разработкой ПО, которая остается актуальной и сегодня.
Эдсгер Дейкстра — «Программирование как искусство» (A Discipline of Programming)
Книга о философии программирования и подходах к созданию элегантных решений.
Обзор паттернов
Марк Ричардс, Нил Форд — «Основы архитектуры программного обеспечения» (Fundamentals of Software Architecture)
Рассматриваются ключевые архитектурные стили и паттерны, а также методы оценки и выбора подходящей архитектуры
Книги по высоконагруженным системам
Мартин Клеппманн — «Проектирование данных: построение надёжных, масштабируемых и поддерживаемых систем» (Designing Data-Intensive Applications)
Эта книга — мастрид для всех, кто работает с высоконагруженными системами. Она охватывает ключевые темы:
базы данных, распределённые системы, обработка данных, согласованность и отказоустойчивость.
модели данных (реляционные, графовые, документоориентированные).
логи и брокеры событий (Kafka, RabbitMQ).
алгоритмы репликации и распределённые транзакции.
Томас Эртл, Томас Фишер — «Высоконагруженные приложения» (Web Scalability for Startup Engineers)
Практическая книга, которая объясняет, как проектировать масштабируемые приложения. Особенно полезна для стартапов и тех, кто начинает работать над высоконагруженными системами.
Темы:
Масштабируемость базы данных.
Балансировка нагрузки.
Основы распределённых систем.
Без классификации
Современный подход к программной архитектуре: сложные компромиссы. Нил Форд, Марк Ричардс...
Здесь только те, что переведены на русский язык
brutfooorcer
11.01.2025 18:13Хорошая статья, но есть "но": в начале вы жестко критикуете микросервисы, описываете ряд проблем, а потом внезапно первым решением предлагаете микросервисы. Вам не кажется это странным?
Я не имею ввиду, что пример плох, я имею ввиду, что он не коррелирует с начальным тезисом статьи "микросервисы вам не нужны". Нужны, получается, а все описанные минусы вы получите в предложенном вами же решении)
Другой вопрос, что делить на МС надо с умом. Но про это ни слова в начальном тезисе - там только минусы микросервисов. Даже без перечисления плюсов.
Dhwtj Автор
11.01.2025 18:13Честно говоря, перечитывать и править статью уже не хочу: завтра её читать уже никто не будет. Формат у Хабра такой.
Но если я буду писать новую статью я учту что многие ставят знак равенства между "имеются (микро)сервисы" и "каждый домен в отдельном небольшом микросервисе, тысячи их!"
Микросервис это не про размер. Просто, термин так сложился, чтобы от SOA отличать
И мне не нравится выражение "делить на МС". Скорее, отделять от монолита.
sergey_prokofiev
Достаточно неплохая обзорная техническая статья. Но тут главное архитекторское описано очень вскользь: требования диктуют архитектуру. И работа с требованиеми - важнейший кусок архитектурной работы. А это уже не только технические решения.
Dhwtj Автор
Спасибо за комментарий.
Здесь рассматриваются исключительно вопросы масштабируемости. Рассмотреть в требованиях насколько критична для бизнеса некосистентность тех или иных данных и соответственно можем ли мы применить в этом месте инструменты повышения производительности, которые плохо скажутся на консистентности? Конечно, это необходимо.
Прочитал вашу статью о том что микросервисы необходимы для fast deploy. Не соглашусь что в монолите изменение одного модуля приведёт к полному регресс тестированию всего приложения. Статические анализаторы позволяют доказать независимость модулей и что зависимости не протекли в другие модули. Это вопрос к квалификации QA и если он это не умеет в монолите, то команда на ровном месте огребет проблемы микросервисов.
sergey_prokofiev
Это прекрасно, но получить консистентную систему над которой работают 10 команд одновременно можно, но сложно. Обычно это требует многих междукомандных согласований, что отдельная дисциплина спецолимпиады. Практика это подтверждает, в большинстве случаев релизы монолитов случаются редко, раз в несколько месяцев. А раз так - то статистический анализ вам покажет, что все во всех модулях поменялось. И привет регрессия.
Я не отрицаю, что можно и монолиты релизить раз в неделю, но на масштабе это работает очень плохо, откуда собственно говоря вся эта мода на микросервисами с их огромными недостатками.
Dhwtj Автор
А в чем проблема? Одна команда делает одну DLL, другая другую. Поверхность соприкосновения минимальная и контролируемая. Если меняется контракт то в микросервисах некоторое время поддерживают обе версии. При минимальных усилиях в монолите тоже можно поддерживать две версии функционала через конфигурации. Запрос пойдет по той ветке которая нужна. Старая версия закончит обработку по тайм-ауту и будет удалена.
Зато у нас в монолите быстрые и надёжные вызовы кода без ретраев и тайм-аутов, быстрые join и так далее.
Просто я немного задолбался поддерживать аналитическую систему в географически распределенной системе источников данных. Была сложная самописная логика повторов, тайм-аутов, выравнивания нагрузки и circuit breakers (предохранителей) с высокими требованиями к надёжности и отсутствию искажений данных из-за некосистентности данных. Не помогли никакие логеры и быстрый деплой тоже не помог. Помогло переписывание ядра с понятной, сконцентрированной бизнес логикой, state machine, отсутствием скрытых состояний и с нулевым доверием ко всему io
Обычно это решается человеком который там живёт и которого не перекидывают с одного продукта на другой по любому чиху
sergey_prokofiev
В теории я с вами согласен. На практике такое возможно и бывает, но почему то очень редко встречается в литературе, да и в моем опыте. Имея большую команду в сотню человек и огромную кодовую базу и возхможность внести незаметно неявные зависимости для быстрого решения срочных проблем не сомневайтесь, это будет сделано как только так сразу. И опять таки, повторюсь, весь этот микросервисный хайп - не от статистически хорошей истории жизни с монолитами.
Знаете анекдот про дурака в церкви и стеклянный буй? Если у вас был один(или 5) негативных кейсов, это не говорит ровным счетом ничего. Если конечно это не кейсы масштаба амазон или нетфликс.
Dhwtj Автор
Статический анализатор кода должен помочь. Хотя, у микросервисов гарантии сильнее, согласен. Примерно как топором по проводке.
Ну, кейсы нефликс на себя натягивать тоже глупо.
Слишком часто встречал раздувание штата чтобы запудрить глаза инвесторам или чтобы поднять свою значимость и незаменимость. Да и многие отказываются от микросервисов потихоньку, соединяют обратно в монолит(ы)
sergey_prokofiev
неявное использование кеша для прокидывание контрактов и даже sick(!) stack trace, походы в чужие схемы данных из хранимок в сотни строк, изменение чужих данных из этих же хранимок с неявным ослабление секурити, вызов кода минуя необходимые слоя и какой хери я только не видел. В микросервисах как минимум контракты можно жестко контролировать, внутри тоже зачастую ад и израиль творится, но оно локализировано и (почти)гарантированно не расползается. Что позволяет масштабироваться до сотен человек индусов за чашку риса в месяц и при этом быть корммерчески успешными.
Dhwtj Автор
Ну, не буду спорить.
Но посыл моей статьи что микросервисы не нужны только для масштабирования (Scalability, может вы имеете в виду Extensibility? Или вообще, расширяемость команд?) и вообще для производительности. Если нет проблемы развития большой и сложной кодовой базы или проблемы быстрого деплоя так и не нужны совсем. Для остального есть
Mastercardsergey_prokofiev
Если мы говорим о Scalability, то микросервисы имеют минорные бенефиты - скейлиннг разных частей системы по разному. Но это реально мелочи и монолитом можно достичь того же чуть бОльшими приседаниями и значительно бОльшим размером контейнеров.
Поэтому как я в статье написал - микросервисы нужны для решения организационных проблем крупных команд - начиная от человек 50-70 на проекте.
Наверное самой правильной метрикой будет TTM, Time to Market - опять таки на масштабе ОТ 50-70 человек в команде.
Дык я ж не спорю. Более того, я всегда за то чтобы стартовать "проект с нуля" с монолита - быстрей, проще, рефакторинг в разы дешевле. Обычно стартуют одной командой, и если выстрелило - то в короткие сроки может образоваться 3-5-10 команд. И тут "хорошо структурированный монолит легко бьется на микросервисы"(ц) и мы получаем и быстрый старт монолитом и относительно безболезненно переживаем рост.
Dhwtj Автор
Насчёт time to market продукта в целом и его фич не могу с уверенностью сказать необходимы микросервисы или можно обойтись. Просто не работал в больших командах
ruomserg
Скажите, откуда пошло заблуждение, что "...требования определяют архитектуру" ? Если вы занимаетесь созданием системы по требованиям - это обычная инженерная работа. Архитектуры в этом считай что и нет. Архитектура начинается тогда, когда вы строите систему под требования которые пока неизвестны, или может быть даже пока не существуют. Соответственно архитектор закладывает в систему точки расширения и масштабирования, хотя прямых показаний к этому в настоящий момент нет. И поскольку все эти точки расширения стоят денег - то искусство архитектора состоит в том, чтобы сбалансировать будущую стоимость содержания и рефакторинга системы и текущую стоимость избыточной адаптивности закладываемой прямо сейчас...
На более доступном языке - когда инженера просят построить дачный домик с конюшней, чтобы рано утром выезжать на коне кататься в поле - он имеет полное право сделать дом, в котором в одной комнате будете жить вы, а в другой - конь... А архитектор понимает что у вас потом появятся жена и дети, и они могут не разделять вашу любовь к конному спорту, поэтому комнат надо больше чем две, а конюшня должна быть отдельной. Ибо опыт развития человечества...
Dhwtj Автор
Архитектура не только и не столько учитывает текущие требования, но и определят стратегию развития продукта
sergey_prokofiev
И делает это, опираясь на требования. Как правило - нефункциональные. Пример:
функциональное требование требование, одинаковое для двух проектов: "я хочу смотреть видео в браузере, загруженное кем то на сервер".
В проекте 1 к этому функциональному требованию идет в нагрузку нефункциональное: "загружать видео будет моя жена раз в неделю и смотреть буду только я 3 раза в неделю ближайшие лет 20 это не изменится"
В проекте 2 к этому функциональному требованию идет в нагрузку нефункциональное: "загружать видео будут со старта 100к человек раз в день и смотреть 1млн 5 раз в день" и следом assumption "через 3 года мы планируем маcштабироваться на 100млн загрузок в день и 1млрд просмотров в день".
Определяет ли архитектура стратегию развития продукта, если будет в обоих случаях следовать требованиям? Безусловно, если архитектор все сделает правильно. Но в обоих случаях он не будет демонстировать некое "искусство угадывания несуществующих требований", а просто решать техническую задачу, опираясь на факты.
Dhwtj Автор
Не нужно угадывать несуществующие требования.
Но некоторый задел обычно оставляют. Примерно как в метро оставляют в тоннеле прямые участки с нужным расстоянием между тоннелями если выдвигалась идея построить тут станцию когда-нибудь.
sergey_prokofiev
Правильно. Этот "задел" обсуждают и подтверждают с бизнесом и помещают в секцию Assumptions. Затем работают с ними как и с остальными требованиями. Банально потому что бизнес обычно лучше понимает, в какую сторону нужен "задел" побольше, насколько "побольше" с цифрами и когда этот "задел" реально потребуется. А в какую сторону "задел" нафиг не нужен и никогда нужен не будет.
ruomserg
У вас очень оптимистическое понимание бизнеса. Я имел (не-) счастье видеть процесс по обе стороны баррикад: как со стороны разработки, так и со стороны бизнеса. В подавляюшем большинстве случаев - бизнес нихрена не знает. В некоторых случаях - ответственные люди выдают в качестве assumptions желаемое за действительность. Другие - общественно-приемлемые ответы и цифры. Третьи говорят что-то с потолка чтобы окружающие продолжали считать их умными... Клиентов, которые честно говорят "х его знает" там, где не знают - по пальцам пересчитать (и я их особо ценю за это!). Поэтому архитектор должен конечно слушать бизнес - но систему он строит с пониманием: не все что ему говорят - правда, а правда то - что часть требований к ней ему не говорят (и о них даже не догадываются).
Хотите пример архитектуры близкий к идеальному - посмотрите на себя. У вас примерно столько суставов, чтобы вы могли дотянуться до любой точки себя (хотя на спине и без особого удобства). Никто не знает в каком месте у вас вскочит прыщ или вы себе всадите занозу. Делать каждую руку с количеством суставов как у змеи - дорого и ненадежно. Сделать слишком мало суставов - можно помереть от заражения крови просто потому что не можешь дотянуться и вытащить щепочку. Так же и в ПО: задача архитектора - используя знания о предметной области и общую логику и опыт развития аналогичных систем заложить ровно столько точек расширения и конфигурируемости, чтобы и не умереть завтра от того что система ни в какую не удовлетворяет изменившимся требованиям, но и не дать ей умереть от чрезмерной стоимости еще на этапе проектирования и кодировнаия...
Dhwtj Автор
Это да. Немного бесит, когда основные компетенции по бизнес процессам не у бизнеса, а у разработки (причём, часто и не у аналитика / продакта, а именно у кодера)
sergey_prokofiev
Может, ну его нафиг такие "бизнесы"? :)
sergey_prokofiev
У меня реалистическое понимание бизнеса - такое как вы описали тоже бывает, и я такими "бизнесами" работаю в исключительных случаях.
Это так же естественно для манагеров, как для кодеров - промахиваться в 3 раза с эстимейтами. И с тем и с этим можно и нужно работать, инструменты описаны лет 10-15 назад минимум.
И работа архитектора - эти требования выявить, обсудить и законфирмать. Для этого, неповерите, тоже есть методики, которые тоже описаны в тех же талмудах.
А вот "партизанить отсебятину" - это как раз фейспалм. Это может сработать, если у вас хороший опыт в конкретном сегменте конкретного бизнес домена и вы там сами все знаете лучше типимчного манагера. А вот шаг вправ-влево - и вероятность "приплыть" моментально подскакивает до 100%. В соседней ветке есть прекрасный гипотитический пример необходимости бассейнов на последнем этаже зданий :)
ruomserg
А не надо лезть в домены, в которых ничего не понимаешь. Архитектура дворца и архитектура моста - это разные архитектуры. У нас в 2000-е годы вдруг пришло поветрие, что менеджеру больше не нужно иметь опыта в домене: мол хороший менеджер сегодня может управлять типографией, а завтра - автомобильным заводом... Результаты в принципе можно наблюдать за окном.
А теперь вы пытаетесь представить дело так, что уже и архитектору не нужен опыт в домене: сегодня он проектирует интернет-магазин, завтра healthcare, послезавтра - комплекс ПО для авионики.
Я резко против этого (и по этой причине мы до крови сремся с архитектами в одной любимой организации). Если архитектуру понимать как "архитекты" из консалтинга - то есть когда вершиной архитектуры считается подготовленный ответ на RFP клиента, то да - не нужен опыт домена, достаточно по кволити-атрибутам подобрать тактики и записать в ахитектуре-десижн-лог. Если же целью архитектуры является стабильный жизненный цикл системы - то ой! Без опыта работы в домене, широкого кругозора и знания тактик (в том числе, но не в первую очередь) - удачи не видать...
sergey_prokofiev
Это пошло из разных книжек, написанных дядьками с десятками лет проверенного опыта.
В этих самых книжках такие требования называются Assumptions и они обсуждаются с бизнесом наравне с остальными требованиями - внезапно у бизнеса зачастую есть понимание в каких местах будет масштабирование и "искусство" заключается в том, чтобы правильно вытрясти из бизнеса перспективы роста, отделить зерна от плевел и дальше начать техническую работу. В некоторых книжках техническую работу предлагают свести к выбору Architecture Tactics из описанного набора согласно требованиям и вуаля. Читайте книжки, меньше будет "проектировать под непонятно что" и "творчества".
Dhwtj Автор
Опять прибегну к аналогии: архитектура несущих стен в доме позволяет свободную планировку комнат. Гибкость в строго определенных пределах и пока эта гибкость не становится слишком дорогой.
А вот например бассейн на верхнем этаже никто делать не будет: перекрытия рухнут, архитектура такого изменения не допускает в принципе!
Надо было сделать задел? Вряд-ли. Слишком дорого и маловероятно что заказчик это оплатит
sergey_prokofiev
Вот вы, к примеру, проектируете отель и приняли решение что бассейн на последних этажах не нужен. Вы ж так и написали. Так и спроектировали и затем строители построили. А спустя некоторое время работы отеля, к вам приходит заказчик и говорит: я решил последний этаж переделать на пентхаус. Вы ж там комнаты даете без проблем переделывать? Значит мы переделакем и мне нужна какая то фигня - 4 бассейна на последнем этаже. И усе.
А причина в том, что вы положились на свой опыт. Самостоятельно сделали предположения и из них выбрали точки расширения Не уточнили с заказчиком, потребуются ли бассейны на последнем этаже - он бы вам моментально ответил "да, вероятность этого высока, я думаю над пентхаусом но надо будет посмотреть реальный спрос".
ruomserg
Из своего опыта - я позволю себе с вами не согласиться. Раньше в ИТ господствовала теория, что МОЖНО составить точные требования на любую систему. И если мы их не имеем - значит мы или ленивые жопы, или не нашли нужных людей и не задали им нужные вопросы.
Я имею утверждать что на сколько-нибудь сложную систему требования составить НЕЛЬЗЯ, если только вы не можете их потом прибить к стене в виде ограничений по эксплуатации (то есть ваши assumptions представляют собой самосбывающийся прогноз, а не требования в классическом понимании).
Соответственно - все идеи из книжек что бизнес способен разумно выработать assumptions под сложную систему - это сродни гениальной идее мышей привесить кошке на шею колокольчик. Да, это сработает если осуществить - и нет, это неосуществимо.
Собственно, вся идея Agile у вас идет ровно от идеи, что будущего не знает никто: ни ИТ, ни бизнес. Поэтому нужен процесс, который позволит как-то жить даже при том, что будущее вам известно только на ограниченный период, и без деталей. И задача архитектора системы - поддерживать систему в таком состоянии, чтобы она и смогла адаптироваться к неизвестным нам пока деталям будущего, и не оказалась бесконечно дорогой и долгой в постройке "здесь и сейчас". При этом, никакие рецепты и серебряные пули тут невозможны. Иначе бы не нужны были архитекторы... Архитект на то и архитект, что имеет широкий кругозор, общие знания, и НЕСЕТ ОТВЕТСТВЕННОСТЬ за принимаемые им решения, а не просто по таблице из книжки выписывает тактики после requirements engineering workshop...
Dhwtj Автор
Ну, совсем без знаний и разумных предположений никак нельзя.
В остальном согласен.
ruomserg
Ну тогда предложу компромисс: будущего на горизонте срока жизни большой системы сколько-нибудь детально не знает никто. Но жить и работать все-равно надо...
sergey_prokofiev
Welcome to Agile.
Хотя есть очень сложные проекты, основные требования к которым разрабатываются на ранних этапах и потом меняются относительно мало. Например проект авианосца. Или Бурдж-Халифа.
Если вы чего то не знаете и не умеете - то это не значит что остальные не знают и не умеют. Посмотрите на тот же TOGAF - специально для больших и крупных кейсов фреймворк, который любят разные ентерпрайзы. Причем там 2 уровня сертификации дял архитекторов, и один - для бизнеса. И представляете, есть бизнес который проходит эту сертификацию и успешно использует в реальных проектах на десятки-сотни человеколет.
ruomserg
Разумеется - если вы такой бизнес, который фактически является монополистом для домена, и будущее в домене - фактически определяется внутри бизнес-структуры - то отчего бы вам и не TOGAF?! Там есть другая особенность - пока вы сертифицируетесь по TOGAF и ведете проект как там написано, у нормального бизнеса скорее всего кончатся деньги. Поэтому шутят, что все проекты по TOGAF успешны, просто потому что о неудачных некому рассказывать...
Но если вы еще и являетесь со своим проектом частью государства, или просто too big to fall - то да, вы можете жить так, как будто знаете в деталях будущее на годы вперед. К счастью, это может себе позволить меньшинство бизнесов - иначе экономика бы рухнула под грузом неэффективных решений.