Материализованные представления, CQRS и CDC в микросервисной архитектуре

микросервисы в Big Data, архитектура данных, шаблоны проектирования микросервисов, архитектура микросервисов паттерны CQRS API Composition примеры применения, архитектура данных, CDC архитектура данных примеры реализации, архитектура микросервисных систем, потоковые базы данных, архитектор данных дата-инженер проектирование микросервисов примеры курсы обучение, Школа Больших Данных Учебный Центр Коммерсант

Как материализованные представления в потоковой базе данных с CDC-подходом и шаблоном CQRS позволяют реализовать масштабируемую и высокопроизводительную систему с микросервисной архитектурой для транзакций и аналитики данных в реальном времени. Разбираемся с паттернами проектирования микросервисов на примере интернет-магазина.

Что не так с шаблоном композиция API и другие проблемы микросервисной архитектуры в управлении данными

Микросервисная архитектура для распределенных систем позволяет обеспечить гибкость, масштабируемость и отказоустойчивость. Однако, как мы уже упоминали здесь, запрос данных из нескольких микросервисов в режиме реального времени может оказаться сложной задачей, поскольку для этого могут потребоваться сложные и трудоемкие операции извлечения данных. Материализованные представления вместе с паттерном проектирования разделения ответственности команд и запросов (CQRS, Command Query Responsibility Segregation) могут решить эту проблему, обеспечивая эффективный запрос данных микросервисов в режиме реального времени.

В качестве примера возьмем интернет-магазин с микросервисной архитектурой. Разделим большую систему по микросервисам на основании ключевых объектов управления: товары, каталоги, клиенты, запасы и заказы. Каждый микросервис отвечает за обработку определенного домена или бизнес-функции и хранение данных в своем собственном хранилище данных, реализуя шаблон Database per Service.

Без материализованных представлений запрос данных из нескольких микросервисов в режиме реального времени может быть затруднен. Например, когда клиент ищет продукт на веб-сайте, необходимо получить информацию о продукте, каталог, цены и состояние запасов из различных микросервисов. Это приводит к множеству двусторонних запросов к разным микросервисам, увеличивая время отклика и нагрузку на базы данных. Самое простое решение, чтобы агрегировать клиентские запросы к нескольким микросервисам в одном вызове API.

Это решение соответствует шаблону композиции API (API Composition). Суть этого паттерна в том, что он реализует запрос, вызывая сервисы, владеющие данными, и выполняет объединение результатов в памяти. Этот прием часто использует другой шаблон проектирования микросервисной архитектуры, шлюз API (API Gareway). Шаблон композиции API является достаточно простым в реализации. В частности, реализовать его можно с помощью технологии GraphQL, которая позволяет клиенту запрашивать только нужные данные из нескольких источников в одном запросе, выполняя федерализацию нескольких схем данных. Подробнее про GraphQL мы писали здесь.

API Composition microservice pattern
Шаблон проектирования композиция API в микросервисной архитектуре

Однако, для GraphQL характерны риски доступа клиента к непредназначенным для него данным. Кроме того, при использовании шаблона композиции API некоторые запросы могут привести к неэффективному объединению больших наборов данных в памяти. Поэтому для этого шаблона характерны проблемы с масштабируемостью и обслуживанием. Также такое архитектурное решение приводит к тесной связи между микросервисами, что считается антипаттерном. Сильная связность между микросервисами противоречит самой идее микросервисной архитектуры. В частности, при запросах к микросервисам необходимо знать структуру данных, возвращаемую запрашиваемыми микросервисами. Кроме того, усложняется реализация, поскольку требуется дополнительная логика для агрегирования и объединения данных из нескольких микросервисов. Композиция API может привести к дополнительным потерям производительности, поскольку микросервису оркестратора нужно дождаться ответов от нескольких микросервисов, прежде чем возвращать результат клиенту. При этом не получиться обеспечить обновление данных из нескольких микросервисов в режиме реального времени. Если данные в запрошенных микросервисах часто изменяются, композиция API может не отражать самые последние данные, что чревато снижением качества данных и устаревшеми сведениями в результатах запроса. Альтернативой является использование материализованных представлений и CDC-подход, что мы рассмотрим далее.

CDC, CQRS и запросы с материализованными представлениями

Изменим архитектуру проектируемой системы, используя захват измененных данных (CDC, Change Data Capture) и материализованные представления для оптимизации запросов к микросервисам в режиме реального времени и повышения производительности.

CDC CQRS микросервисная архитектура паттерны проектирования
CDC и CQRS с потоковой базой данных в микросервисной архитектуре

CDC-подход используется в микросервисах для отслеживания изменений в базах данных. Обычно это реализуется с помощью специализированных продуктов или самописные решения, о чем мы писали здесь. Это позволяет уведомлять несколько микросервисов о любых изменениях данных, чтобы их можно было соответствующим образом обновить. Такой механизм экономит много времени, позволяя работать только с ограниченным объемом измененных данных вместо полного сканирования базы. Чтобы использовать CDC с микросервисами, механизм захвата измененных данных должен быть интегрирован в каждый из них еще на этапе проектирования приложения. При этом необходимо решить следующие вопросы:

  • Как фиксировать изменения данных – через триггеры на таблицах БД, опросы, логи или готовые решения типа Debezium. Триггеры, как частный случай хранимых процедур, могут использоваться для выполнения действия при определенных событиях. Подробнее о сходстве и различии триггеров и хранимых процедур мы писали здесь на примере Greenplum. Опрос регулярно запрашивает базу данных, чтобы узнать, были ли внесены изменения. Логи фиксируют всю активность базы данных, включая изменения, и могут использоваться для обработки в реальном времени. Каждый из подходов имеет свои достоинства и недостатки, которые следует учитывать для каждого конкретного сценария.
  • Как передавать изменения данных – синхронно или асинхронно. Синхронная связь полезна для кратковременных транзакций, а асинхронная связь идеальна для длительных процессов.
  • Как обеспечить согласованность данных между сервисами – через использование распределенных транзакций, что чревато проблемами с производительностью, или через согласованность в конечном счете, когда каждый сервис работает со своими собственными данными и в конечном итоге становится согласованным с другими приложениями.

В рассматриваемом примере интернет-магазина CDC-подход можно использовать для управления запасами. Например, каждый раз, когда товар добавляется, обновляется или удаляется из каталога, механизм CDC фиксирует изменение и отправляет его в микросервисы, отвечающие за управление товарами и запасами. Так CDC позволяет поддерживать актуальность наличия товаров, гарантируя клиентам постоянный доступ к нужным им продуктам.

CDC позволяет реализовать инкрементные обновления хранилища данных, фиксируя изменения, внесенные в системе-источнике, чтобы загружать только их в DWH. Это сокращает время, необходимое для полной загрузки, и обеспечивает постоянную актуальность данных в хранилище данных. Также CDC можно использовать для потоковой передачи данных из нескольких источников с целью их анализа в реальном времени. Наконец, CDC пригодится для обновления моделей AI/ML новыми данными. CDC фиксирует изменения, внесенные в исходную базу данных, и обновляет модели AI/ML новыми данными. Это помогает обновлять ML-модели с использованием самых последних данных, повышая их точность.

Впрочем, помимо CDC-подхода в рассматриваемом кейсе интернет-магазина имеет смысл использовать и другой паттерн управления данными в микросервисной архитектуре – CQRS, суть которого в отделении запросов от команд. CQRS предполагает наличие базы данных представления, которая является доступной только для чтения репликой, предназначенной для поддержки запросов. Приложение поддерживает реплику в актуальном состоянии, подписываясь на события домена, публикуемые сервисом, которому принадлежат данные. Этот шаблон поддерживает несколько денормализованных представлений, которые являются масштабируемыми и производительными. Он позволяет упростить модели команд и запросов, что полезно в EDA-архитектуре, управляемой событиями в реальном времени.

Однако, CQRS как шаблон проектирования, имеет следующие недостатки: повышенная сложность, возможное дублирование кода, задержка репликации и представления, согласованные в конечном счете.

Тем не менее, CQRS позиционируется как альтернатива шаблону композиция API без проблем с масштабируемостью и производительностью. Для реализации CQRS следует определить команды, которые будут изменять данные, и запросы, которые будут считывать данные. Такое разделение позволяет оптимизировать каждую операцию независимо. Например, товары могут храниться и обновляться в классической базе данных, а списки товаров, результаты поиска, история заказов или рекомендации пользователей могут быть материализованными представлениями в потоковой база данных, которые обновляются в режиме реального времени на основе входящих событий.

Материализованные представления — это предварительно вычисленные представления данных, которые хранятся и обновляются независимо от основной транзакционной базы данных. Их можно использовать для оптимизации операций чтения за счет уменьшения сложности и задержки, связанных с запросами к основной базе данных.

Сперва идентифицируем запросы, требующие доступа к данным интернет-магазина в режиме реального времени, например, списки недавно просмотренных товаров. Основная цель здесь — сохранить данные, требуемые службой запросов, в денормализованном формате, чтобы обеспечить быстрый поиск. Материализованные представления денормализованы и оптимизированы для конкретного запроса или представления в пользовательском интерфейсе, чтобы быстрее и эффективнее извлекать данные. Материализованные представления могут быть созданы с использованием баз данных или специализированных систем кэширования. Чтобы получать обновления в режиме реального времени и поддерживать согласованность этих данных, подписавшись на изменения состояния баз других микросервисов, целесообразно использовать потоковую СУБД, например, Rockset, Materialise, RisingWave и DeltaStream. Подробнее о потоковых базах данных, которые поддерживают аналитические операции с непрерывными потоками данных в реальном времени с помощью SQL-запросов, мы писали здесь и здесь.

Потоковая СУБД может принимать данные в режиме реального времени из различных источников в виде потоков событий с помощью CDC-процесса и встроенного коннектора. Потоковая база данных создает материализованное представление, объединяя потоки событий вместе, и поддерживает актуальность представления по мере поступления новых событий обновления, добавления и удаления данных. Например, когда новый товар добавляется в каталог, соответствующее событие фиксируется и используется для обновления материализованного представления списков товаров, гарантируя актуальность и согласованность данных.

Возвращаясь к паттерну CQRS, который предполагает разделение команд и запросов, следует добавить микросервис, который будет обслуживать запросы на чтение, поступающие из пользовательского интерфейса клиентского приложения. Эти запросы API преобразуются в SQL-запросы, которые извлекают данные из материализованных представлений потоковой базы. Например, когда пользователь ищет товар, результаты поиска можно получить из материализованного представления для списков поиска, вместо того чтобы выполнять несколько вызовов API к различным микросервисам.

Таким образом, материализованные представления упрощают логику запросов, заранее агрегируя данные, избавляя разработчика от работы со сложными SQL-запросами со множеством JOIN-операторов. Благодаря оптимизации материализованных представлений под конкретные запросы, можно снизить нагрузку на основную базу данных и повысить общую производительность системы. Материализованные представления в потоковой базе данных могут предоставлять данные в режиме реального времени из нескольких микросервисов, реализуя шаблон CQRS. Разделение операций чтения и записи с предварительным вычислением представления данных также обеспечивает масштабируемость и отказоустойчивость. Потоковая база может быть развернута независимо от основной, что соответствует горизонтальному масштабированию запросов. Наконец, базу данных потоковой передачи можно использовать в качестве резерва на случай, если основная база выйдет из строя.

Узнайте больше подробностей по проектированию и поддержке современных дата-архитектур в проектах аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Источники

  1. https://www.iambobur.com/post/querying-microservices-in-real-time-with-materialized-views
  2. https://microservices.io/patterns/
  3. https://medium.com/@bijit211987/change-data-capture-with-microservices-79fa90aaf0b3
Поиск по сайту