Микросервисы без дублирования данных

19

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

Используя приложение, мы можем захотеть увидеть все товары, которые заканчиваются, и список тех, кто их накопил в прошлый раз, чтобы мы могли попросить их пополнить его снова. Используя описанную выше архитектуру, в службу инвентаризации будет сделан запрос на получение сведений об элементах всех элементов, количество которых меньше 5. Это вернет список, включающий идентификаторы пользователей. Затем в службу пользователей будет сделан отдельный запрос на получение имени пользователя и контактных данных для списка идентификаторов пользователей, полученных из службы инвентаризации.

Это кажется ужасно неэффективным, и не требуется много дополнительных сервисов, прежде чем мы сделаем несколько запросов к API различных сервисов, которые, в свою очередь, делают несколько запросов к базе данных. Альтернативой является репликация сведений о пользователях в данных инвентаризации. Когда пользователь меняет свои контактные данные, нам нужно будет повторить изменение через все другие сервисы. Но это, похоже, не соответствует идее ограниченного контекста микросервисов. Мы также могли бы использовать одну базу данных и распределить ее между различными службами, и у нас были бы все проблемы с интеграционной базой данных .

Какой правильный / лучший способ реализовать это?

Герайнт Андерсон
источник
5
Добро пожаловать в парадокс микро-услуг. То, что кажется более простым, на самом деле может усложнить ситуацию.
Роберт Харви
«Правильный» способ такой же, каким он был всегда: найти способ сделать то, что лучше всего соответствует вашим конкретным целям.
Роберт Харви
1
@RobertHarvey Это всегда так, но я пытаюсь понять микросервисы из учебника. Как только я пойму, как это должно работать в идеальном мире, я с радостью изменю его, чтобы он соответствовал моему сценарию использования.
Герайнт Андерсон
1
Но вы сформулируете свой вопрос с точки зрения эффективности, что является нефункциональным требованием к программному обеспечению. Способ решения проблемы эффективности заключается в непосредственном обращении к базе данных.
Роберт Харви
1
Я собирался написать вопрос точно так же, как ваш. Я до сих пор не вижу преимуществ в MSA для достаточно простых веб-приложений. Я думаю, что во многих случаях модульность может быть достигнута без усложнения вещей.
Glasnhost

Ответы:

10

Я полностью пропустил, где вы должны дублировать.

Главный принцип микро-услуг заключается в том, чтобы служба была единственной властью. Это означает, что инвентаризация и управление пользователями могут быть полностью разделены. Я бы спроектировал управление пользователями так, чтобы оно даже не знало, что система инвентаризации существует.

Но я бы спроектировал систему инвентаризации так, чтобы она никогда не сохраняла ничего о пользователях, кроме идентификатора пользователя. Это решает вашу проблему распространения информации о пользователях.

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

Таким образом, в каждом случае, когда вам нужна последняя информация о пользователе, вы спрашиваете службу информации о пользователе.

candied_orange
источник
@Geraint: Можете ли вы быть более конкретным о том, какое дублирование происходит в вашей системе?
Роберт Харви
1
Благодарю. Дублирование относится к копированию контактных данных пользователей в службу инвентаризации, но вы обратились к этому (т.е. это не требуется). Кажется нелогичным переходить из одной реляционной базы данных, где я мог бы получить данные инвентаризации и пользовательские данные с объединением, к двум отдельным вызовам API, где второй не может начаться, пока первый не вернет результаты. Но я думаю, что это часть оценки того, использую ли я микросервисы или что-то еще.
Герайнт Андерсон
Это тот же трюк, который БД использовала бы, если бы управляла обоими. Вы не копируете информацию о пользователе в инвентарную таблицу. Вы даете ему внешний ключ. Идентификатор пользователя выполняет одинаковую работу для всех служб. Просто сделай это уникальным.
candied_orange
It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinИмейте в виду, что «в идеале» есть один магазин на сервис (или больше!). Таким образом, нет ничего такого, как «соединение» между «границами». Причина проста, БД генерирует связь между сервисами. В отличие от предложения @CandiedOrange, я думаю, мы можем дублировать минимум данных из одного сервиса в другой. Я имею в виду данные, которые вряд ли изменятся. Если этот провал улучшит эффективность и производительность (и то, и другое обязательно), то «за», вероятно,
сместит
@ GeraintAnderson Я имею в виду, если вам нужна эффективность (которая по определению является нефункциональным требованием), есть способы сделать это. Т.е. запрашивать страницы данных из службы инвентаризации (например, 10 элементов), брать каждую страницу и использовать эту страницу для запроса данных из службы пользователя и агрегировать в конце. Таким образом вы сохраняете свои границы, используя параллелизм независимых сервисов. Даже тогда, не беспокойтесь, пока вы не определили его как реальное узкое место приложения, которое должно быть решено - ожидание дополнительных 1/2 секунды на 1-секундной ночной работе ни для кого не имеет значения.
Делиот
11

Мне трудно избежать дублирования данных ....

Согласно электронной книге Microsoft по архитектуре микросервисов , нет ничего плохого в дублировании данных. По сути, дублирование данных увеличивает разделение между службами и, следовательно, усиливает их роль как единого органа. Соответствующий отрывок:

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

Мауриц Моисей
источник
1
Я полностью не согласен. Это делает его сложнее поддерживать. Это заставляет вас осуществлять транзакции между микросервисами, когда что-то нужно добавить, обновить или удалить. Если вы хотите предотвратить одну точку сбоя, вы можете использовать запрос или любой другой тип кэширования.
Алан
1
@AlanSereb Сложнее поддерживать, но дело в том, что иногда у тебя нет другого выбора. Например, что если вам нужно создать FK между объектами, живущими в двух базах данных? Единственный способ обеспечить согласованность при выполнении запросов в локальной БД - это репликация данных. Взгляните на: stackoverflow.com/a/4452586/2255491
Дэвид Д.
Я согласен. Еще один замечательный подход заключается в том, чтобы выбрать маршрут поиска. И
Алан
4

был бы сделан запрос в службу инвентаризации для получения сведений об элементах всех позиций, количество которых меньше 5. Это вернет список, включающий идентификаторы пользователей. Затем в службу пользователей будет сделан отдельный запрос на получение имени пользователя и контактных данных для списка идентификаторов пользователей, полученных из службы инвентаризации.

Определенно да.

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

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

Независимо от того, как вы это делаете, где-то будет код, который, по сути, извлекает список идентификаторов пользователей из системы инвентаризации, передает их в систему пользователей и составляет список данных.

Вопрос, на который вам нужно ответить, касается производительности, технического обслуживания и других «мягких» качеств.

Основным преимуществом микросервисов является масштабирование. Если у вас есть десять тысяч пользователей на одной машине, и это немного вяло, вы можете добавить другую машину, и система станет в два раза быстрее. Добавьте еще восемь, и это в десять раз быстрее. (Линейное масштабирование, вероятно, является оптимистичным, но это идеал, на который можно надеяться.)

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

Если вам не нужно масштабирование, есть еще одно преимущество микросервисов: они модульные . Конечно, монолитные приложения также могут быть модульными, и у вас есть нормализованная база данных и ... но на практике стены между модулями похожи на стеклянные стены в лучшем случае, а линии на песке - в худшем. Микросервисы отделены прочной сталью.

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

И вы не дублируете данные в микросервисах , равно как и в реляционной базе данных (*). В реляционной базе данных вы можете выполнить соединение , и эквивалентно объединить списки в коде, как описано.

Вы также можете добавить представление , эквивалентное добавлению нового сервиса, который выполняет слияние для вас; это приведет к трем запросам; один к новому сервису, а затем этот сервис делает первоначальные два. В реляционных базах данных есть модные вещи, которые оптимизируют представления, которые должны быть реализованы на уровне обслуживания. Вы не получаете это "бесплатно".

Кэширование отличается от дублирования данных тем, что если два значения не совпадают, вы знаете, какое из них неправильное. Он часто используется в микросервисах для повышения доступности за счет согласованности (теорема CAP). Поскольку реляционные базы данных полностью подтверждают доступность на алтаре согласованности, они встречаются реже. Я бы сказал, что в микросервисах нет ничего, что могло бы облегчить кэширование, но на практике кэширование является основной задачей и облегчает кэширование в микросервисах .

(*) Если имеет смысл дублировать данные в микросервисном рое, то, вероятно, это будет иметь смысл в эквивалентной реляционной базе данных.

Odalrick
источник
3
Мне очень понравился твой ответ до тех пор, пока не появилась часть «Не дублируй данные в микросервисах». Я думаю, что есть случаи, когда дублирование данных является правильным подходом. Это повышает отказоустойчивость и автономность. Если служба пользователя вышла из строя, служба инвентаризации может по-прежнему отображать список с низкой инвентаризацией, с которой они запасались последними.
Петр Помпей
1
@peterpompeii Я бы назвал это кэшированием, а не дублированием данных. Дублирование данных - это когда у вас есть два места для обновления для одного элемента, кеширование, когда есть одно место, и автоматическое распространение в другие места. Также я сказал больше, чем реляционный. Если в реляционной базе данных имеет смысл дублировать данные, это имеет смысл в микросервисе. Я думаю, что мы согласны, и эта часть могла бы быть более ясной, но у меня есть только телефон прямо сейчас, поэтому не буду обновлять текст прямо сейчас.
Одалрик
@PeterPompeii Надеюсь, что добавленный раздел о кэшировании решает некоторые ваши проблемы.
Одалрик
1
@ Одалрик, что вы описали, звучит как репликация данных. Репликация и кэширование являются обе формы дублирования данных. Репликация - это когда копия всегда имеет все необходимые данные. Кэширование по требованию. Кеширование может быть пропущено. Кэширование доступности не имеет такого большого смысла, как кэширование производительности. TL; DR, если вы храните полную копию чего-либо с достаточной согласованностью, это гарантирует, что вам никогда не нужно проверять пропуски, тогда это не кеш.
Брэндон
1
@ Брендон Еще одно различие между репликацией и кэшированием заключается в том, как вы узнаете, какие данные неверны, когда есть разница. Репликация определяет некоторые правила объединения данных. Кэширование, с другой стороны, всегда : кеш неправильный.
Одалрик