Микросервис CQRS отдельно строит (пишет) модель запроса и читает модель - PullRequest
2 голосов
/ 06 июля 2019

по сценарию

Получение 60 000 сообщений в минуту из очереди. REST API, обслуживающий данные из этих сообщений 10 раз в минуту.

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

Каждые несколько минут около 60 000 команд отправляются и сохраняются как события с использованием шаблона event-sourcing. Через CQRS фактические данные (не событие) синхронизируются с другой службой, которая хранит их в базе данных. тем временем данные читаются только дюжину раз в несколько минут.

Другими словами. Эта одна служба получает 60 000 операций записи, но только дюжину операций чтения.

Я бы действительно хотел придерживаться шаблонов проектирования микросервисов, также известных как one database per service, но по причинам масштабирования я не вижу, что это возможно в моем сценарии. Запись в базу данных должна значительно масштабироваться больше, чем чтение базы данных.

Я видел похожий вопрос , но в ответе предлагается использовать CQRS, который я уже реализовал. Кто-то сказал мне прежде, чтобы удалить источник событий, но это все еще оставляет мне 60 000 записей и 10 операций чтения.

Какой должна быть моя архитектура для независимого масштабирования операций чтения и записи? Я думаю о создании двух отдельных сервисов, но это будет противоречить шаблону one database per service.

Ответы [ 2 ]

1 голос
/ 09 июля 2019

Успение

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

Проблема

Исходя из этого предположения, разделение этого домена на 2 микросервиса и использование CQRS не решит эту проблему. Почему?

Потому что, если у вас есть микросервис Write и Read, вы обновляете микросервис Read с событиями, которые вы публикуете из микросервиса Write, у вас будут проблемы с задержкой. Это означает, что у вас будет какая-то минимальная задержка около 50-100 миллисекунд (большую часть времени задержка будет больше) пока ваша база данных микросервисов Read не будет синхронизирована с вашей базой данных микросервисов Read. Это нормально, и это то, что вам необходимо учитывать при работе с распределенными системы, использующие очереди.

Исходя из этого, разделение этой части Домена на 2 микросервиса - не лучший подход (опять же основано на моем предположении, что вам нужно читать данные микро-сервисов почти в режиме реального времени).

Возможные решения

Что ты мог сделать? Здесь можно сделать несколько вещей:

  1. Опция - Репликация базы данных и CQRS

    • Часть базы данных Опять же, если вам нужны обновленные данные, вы можете использовать что-то вроде репликации только для чтения вашей базы данных записи. SQL Server предоставляет что-то подобное из коробки. Я использовал это на одном из моих проектов. Это будет означать, что у вас будет другая база данных, где SQL-сервер будет реплицировать ваши данные в другую базу данных на уровне базы данных (это было бы намного быстрее, чем делать целое, публиковать в очереди и использовать сообщение из другого микросервиса). Эта база данных будет точной копией вашей базы данных записи и будет доступна только для чтения. Таким образом, ваши 10 операций чтения будут почти всегда быть в курсе с очень очень низкой задержкой. Вы можете прочитать об этой функции из SQL Server здесь.

    • CQRS часть для бэкэнда Когда дело доходит до CQRS, вы все равно продолжаете использовать его с двумя микро-сервисами (запись и чтение). Микро-сервис Write будет использовать ваш первичный экземпляр SQL Server и ваш микросервис чтения будут использовать реплику только для чтения первичной базы данных. Иметь ввиду что эта реплика только для чтения является отдельной базой данных, работающей на отдельной машине. Исходя из этого, вы будете удовлетворять правилу: «1 база данных на один микросервис». Конечно, эта опция возможна, если вы используете Microsoft Sql Server.

  2. Опция - Использование источников событий для создания материализованных представлений и CQRS на стороне сервера

    • Часть базы данных При таком подходе вы будете использовать материализованные представления, которые будут использоваться для чтения в той же базе данных, что и ваша основная база данных или база данных микросервиса Write. Например, если вы используете PostgreSQL, вы можете использовать Marten (https://jasperfx.github.io/marten/) для получения и хранения событий. Это для .NET, но я думаю, что есть и другие решения для других языков. Хорошая вещь о Marten что вы можете создавать материализованные представления (называемые проекционными представлениями), которые создаются, как только изменяется агрегат / модель. Означает, например, что если вы изменили какой-либо объект Customer с помощью источника событий, вы бы опубликовали событие, которое будет сохранено. в базу данных (используя Мартен). После этого куница обновит ваш проекционный вид (который будет таблицей в вашей БД, как CustomersProjection), применяя только последнее событие. Это очень эффективно, и ваше мнение будет актуальным, как только событие будет опубликовано. Таким образом, вы бы использовали уже существующую реализацию Event Sourcing.

    • Внутренняя часть CQRSсерверная / серверная сторона будет разделена на 2 микросервиса, как в предыдущем подходе. В отличие от другого подхода здесь все будет в одной физической базе данных. Когда дело доходит до CQRS, вы все равно продолжите использовать его, но только на своем уровень сервера / сервера. Когда дело доходит до уровня базы данных, вы физически получаете доступ к одной и той же базе данных из обоих микро-сервисов. Было бы просто логическое разделение, и использование одного и того же БД для обоих также имеет некоторые недостатки. Даже если бы у вас было все в одном к базе данных вы получите доступ только к проекционным видам из микросервиса Read и ко всем остальным таблицам из микросервиса Write. Есть способы, как вы можете обойти это, чтобы добавить ограничение на уровне кода, чтобы не получать доступ к определенным таблицам. Например если вы используете ORM с .NET или Java, вы можете сделать это легко. Для других технологий существуют аналогичные решения.

    • Проблема в том, что вы будете использовать одну базу данных для обеих микро-служб.

  3. Опция - вообще не использовать CQRS для этой части домена

    • Если ваше приложение / домен разделено на микроуслуги для некоторых частей домена, имеет смысл использовать CQRS для разделения операций чтения и записи не только с точки зрения базы данных, но и с точки масштабирования сервера зрения. С точки зрения базы данных хорошо, если вы используете 2 базы данных, вы можете даже выбрать различные технологии для Ваша запись и чтение базы данных. Преимущество заключается в том, что вы можете масштабировать прочитанную часть независимо от Напиши часть и наоборот. В вашем случае, если у вас есть только 10 чтений в 1 минуту, это означает, что у вас нет большого загрузка ваших данных с использованием отдельной базы данных и микросервиса не нужна (и в этом случае я бы даже сказал, что это перебор). 10 загружает больше на тот же сервер в минуту, где записи будут обрабатываться вместе с читает почти без разницы. Но я не знаю, если это только на данный момент или требования будут меняться, и запросы на чтение будут увеличиваться. Пока в этом нет необходимости и Я бы положил все в один микросервис и базу данных. В одном из моих предыдущих проектов у нас был именно тот секнарио, где у нас была огромная архитектура, основанная на микро-услугах, и в части, где мы использовали CQRS, разделяя конкретный субдомен на 2 микроуслуги, имеющие свои выделенные базы данных, но в других частях домена мы не использовали CQRS, поскольку это просто не имело никакого смысла для нас в этой части домена.

Имейте в виду, что эти предложения в некоторых случаях специфичны для некоторых технологий баз данных, таких как SQL Server, PostgreSQL или похоже, но для вас важна идея и подход. Большинство из этих действий могут быть выполнены независимо от используемой вами базы данных.

В целом:

Греховно ли разбивать «одну базу данных на сервис» или это нормально рассмотреть разделение службы в письменной форме (к базе данных) и чтение / представление (из той же базы данных) как один сервис.

Я бы сказал, что для каждого правила есть исключения, и если использование CQRS с 2 дБ усложнит вам жизнь и у вас возникнут проблемы работа с вашей системой или доменом из-за этого означает, что вы не используете шаблон / практику правильно или вы используете неправильный шаблон для вашего случая. Иметь ввиду что шаблоны существуют для решения общих проблем, и если они не подходят для конкретного случая, не используйте их. В смысле микро-услуг все становится еще сложнее, потому что многие вещи адаптированы чтобы соответствовать потребностям вашего бизнеса. Это хорошо, так как цель состоит в том, чтобы предоставить клиенту наилучшее возможное решение. Даже если вы и ваша команда поймете, что можете использовать 2 микро-сервисы и использовать 1 базу данных в качестве лучшее решение, пойти на это. Не делайте это правилом для всей вашей архитектуры, потому что это не практика в микро-сервисахмир, но, как всегда, если у вас есть веские аргументы для этого, вы можете нарушить правило.

Запись в базу данных должна значительно масштабироваться больше, чем чтение базы данных.

ЭтоС точки зрения сервера и сервера это не проблема, так как вы можете масштабировать по горизонтали и запускать столько экземпляров этого микро-сервиса, сколько вам нужно.Например, 10 одновременно работающих только для обслуживания записи - это нормально.10 операций чтения в дополнение к этому в минуту - в этом масштабе не о чем беспокоиться (в смысле, когда все в одном микросервисе - чтение и запись).Когда дело доходит до масштабирования базы данных.Это другая тема.Разделение операций чтения на выделенную базу данных не поможет масштабировать данные, имеющиеся в базе данных записи.Чтобы решить эту проблему, необходимо учитывать и другие вещи: оптимизация запросов, добавление правильных индексов, разделение данных, историзация данных и т. Д.Но это уже другая тема.

Резюме:

Я бы предложил использовать вариант 1., но только если вы используете SQL Server.С другой стороны, если вы обнаружите, что ваша текущая технология баз данных предоставляет сопоставимую функцию, вы можете реализовать ее и с ней.Если это не сработает для вас, я бы предложил перейти с 3. Варианта и полностью отказаться от CQRS для этой части (или домена).Мне кажется, вам это не нужно для этого случая.

0 голосов
/ 07 июля 2019

Чтобы найти ответ на свой вопрос, вам, возможно, придется объединить мыслительные процессы Microservices и CQRS.

Две точки зрения, которые помогут вам обдумать эту проблему:

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

  2. С истинным CQRS вы склоняетесь к не имеющему отношения/ связь между частями записи и чтения данных .Прекрасным примером этого является использование СУБД для хранения стороны записи и использование хранилища документов (например, MongoDB или даже индекса, подобного ElasticSearch) для стороны запроса из-за ее поддержки структуры агрегированных данных.

Таким образом, два отдельных сервиса - это путь, ИМХО, если вы хотите иметь возможность масштабирования по отдельности и не хотите конфликтов между операциями записи и чтения.

...