Как обрабатывать ограничения внешнего ключа при переходе от монолита к микросервисам?

18

Моя команда мигрирует из монолитного приложения ASP.NET в .NET Core и Kubernetes. Изменения в коде, кажется, происходят так же хорошо, как и следовало ожидать, но где моя команда сталкивается с большим количеством разногласий вокруг базы данных.

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

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

Я считаю, что их потеря является необходимым компромиссом при переходе на микросервис и получении преимуществ масштабируемости, которые приходят с этим. Пока мы правильно выбираем наши швы и развиваемся вокруг них, все должно быть в порядке. Другие члены команды непреклонны в том, что все должно оставаться в одной и той же монолитной базе данных, чтобы все могло быть КИСЛОТОМ и иметь ссылочную целостность везде.

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

Рэймонд Салтрелли
источник
5
Ссылочная целостность чрезвычайно ценна. Действительно ли масштаб базы данных является узким местом здесь? Вам действительно нужна масштабируемость в стиле микросервиса? Вы лучше меня знаете, подходит ли это изменение в архитектуре для вашей организации, но учтите, что оно просто не подходит для многих случаев использования. Могут быть и другие способы масштабирования с более привлекательными компромиссами. Например, если запросы к базе данных в секунду слишком высоки, возможно, репликация базы данных - это все, что нужно. И вы можете горизонтально масштабировать веб-серверы, не используя микросервисы.
Амон
Хорошие моменты. Мы рассмотрим некоторые из этих вариантов краткосрочной выгоды. Однако переход к микросервисам - долгая игра. На мой взгляд, это позволит нам масштабироваться годами, а не месяцами.
Рэймонд Солтрелли
3
Я уверен, что ваши клиенты будут в восторге от того, что заказ, который они разместили на 0,05 мс быстрее, будет отменен, потому что кто-то другой заказал такой же продукт, когда на складе остался только один.
Энди
@amon Сделайте это ответом, и я буду голосовать. Это хороший вопрос, и плюсы и минусы должны быть справедливо представлены.
Маккотл
@ mcottle хорошо, готово!
Амон

Ответы:

19

Не существует четкого решения, потому что это полностью зависит от вашего контекста - в частности, от того, в каких измерениях предполагается масштабировать вашу систему и каковы ваши реальные проблемы. Является ли база данных вашим узким местом?

Этот (к сожалению, довольно длинный) ответ будет звучать примерно так: «Микросервисы плохие, монолиты на всю жизнь!», Но это не мое намерение. Я хочу сказать, что микросервисы и распределенные базы данных могут решать различные проблемы, но не без собственных проблем. Чтобы привести веские аргументы в пользу вашей архитектуры, вы должны показать, что эти проблемы не применимы, могут быть смягчены и что эта архитектура является лучшим выбором для нужд вашего бизнеса.

Распространять данные сложно.

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

Атомарные обновления, транзакции, непротиворечивость / ссылочная целостность и долговечность чрезвычайно ценны, и от них не следует отказываться от поспешных решений. Нет смысла иметь данные, если они неполные, устарели или прямо неверны. Если у вас есть ACID в качестве бизнес-требования, но вы используете технологию баз данных, которая не может предложить его «из коробки» (например, многие базы данных NoSQL или архитектура DB-per-microservice), тогда ваше приложение должно заполнить пробел и предоставить эти гарантии.

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

    Например, рассмотрите возможность анализа Jepsen хорошо известных систем распределенных баз данных , возможно, начиная с анализа Cassandra . Я не понимаю половину этого анализа, но TL; DR состоит в том, что распределенные системы настолько сложны, что даже ведущие отраслевые проекты иногда ошибаются, и это может показаться очевидным задним числом.

  • Распределенные системы также подразумевают большие усилия по разработке. В определенной степени существует прямой компромисс между затратами на разработку или потерей денег на более мощном оборудовании.

Пример: свисающие ссылки

На практике вы должны смотреть не на информатику, а на требования своего бизнеса, чтобы понять, можно ли и как смягчить действие ACID. Например, многие отношения с внешними ключами могут быть не такими важными, как кажется. Рассмотрим товар - категория n: m отношений. В СУБД мы можем использовать ограничение внешнего ключа, чтобы только существующие продукты и существующие категории могли быть частью этих отношений. Что произойдет, если мы представим отдельные продукты и категории услуг, а продукт или категория будут удалены?

В этом случае это не может быть большой проблемой, и мы можем написать наше приложение, чтобы оно отфильтровывало любые продукты или категории, которые больше не существуют. Но есть компромиссы!

  • Обратите внимание, что для этого может потребоваться уровень приложения для JOINнескольких баз данных / микросервисов, который просто перемещает обработку с сервера базы данных в ваше приложение. Это увеличивает общую нагрузку и требует перемещения дополнительных данных по сети.

  • Это может испортить нумерацию страниц. Например, вы запрашиваете следующие 25 продуктов из категории и отфильтровываете недоступные продукты из этого ответа. Теперь ваше приложение отображает 23 продукта. Теоретически, страница с нулевым товаром также возможна!

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

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

Пример: одновременные заказы

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

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

Но, возможно, это не вариант, например, для одновременных настроек. Рассмотрим 3000 человек, спешащих купить билеты на концерты в течение первых 10 секунд, и давайте предположим, что для изменения доступности потребуется 10 мс. Какова вероятность продажи последнего билета нескольким людям? Зависит от того, как обрабатываются эти коллизии, но используя распределение Пуассона, λ = 3000 / (10s / 10ms) = 3мы получаем P(k > 1) = 1 - P(k = 0) - P(k = 1) = 80%шанс коллизии за интервал 10 мс. Возможность продажи и последующей отмены большинства ваших заказов без мошенничества может привести к интересному разговору с вашим юридическим отделом.

Прагматизм означает сбор лучших черт.

Хорошей новостью является то, что вам не нужно переходить на модель распределенной базы данных, если это не требуется в противном случае. Никто не отменит ваше членство в Микросервисном клубе, если вы не будете «правильно» использовать микросервисы, потому что такого клуба нет - и нет единственно верного способа создания микросервисов.

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

Вы можете масштабировать без микросервисов.

Микросервисы имеют два основных преимущества:

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

Если независимое масштабирование не требуется, микросервисы менее привлекательны.

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

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

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

У вас есть сильное экономическое обоснование?

Вы знаете о бизнес-потребностях вашей организации и поэтому можете создать аргумент для архитектуры базы данных на микросервис на основе анализа:

  • что требуется определенный масштаб, и эта архитектура является наиболее экономически эффективным подходом для достижения этой масштабируемости с учетом возросших усилий по разработке такой установки и альтернативных решений; и
  • что ваши бизнес-требования позволяют ослабить соответствующие гарантии ACID, не приводя к различным проблемам, подобным тем, которые обсуждались выше.

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

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

Амон
источник
Отличный ответ, спасибо. Можете ли вы уточнить это утверждение? Вы имеете в виду, что сокращение количества процедур может сильно повлиять на производительность? Вы упоминаете хранимые процедуры. Сокращение их может иметь такой большой эффект, что любые другие дискуссии о масштабируемости будут спорными.
алан
1
@alan Хранимые процедуры можно использовать хорошо, но они создают две проблемы с производительностью: (1) Более сложные запросы труднее оптимизировать для базы данных. (2) Использование sprocs означает больше работы на сервере БД. OP хочет разделить базу данных для дальнейшего масштабирования, но избежание сложных sprocs может уже обеспечить этот запас. Конечно, sprocs и сложные запросы также могут быть хороши для производительности, например, когда они минимизируют объем данных, которые должны быть переданы из БД для ответа на запрос. Разделение БД усугубит эту проблему, когда требуются межсерверные соединения.
Амон
0

Я считаю, что оба подхода правдоподобны. Вы можете выбрать масштабируемость, жертвуя преимуществами ACID и монолитных баз данных, а также придерживаясь текущей архитектуры и жертвуя масштабируемостью и гибкостью более распределенной архитектуры. Правильное решение будет исходить из текущей бизнес-модели и стратегии бизнеса на ближайшие годы. Чисто с технологической точки зрения есть трудности, сохраняющие его монолитность, а также переход к более распределенному подходу. Я бы проанализировал систему и посмотрел, какие приложения / модули / бизнес-процессы более важны для масштабирования и оценки рисков, затрат и выгод, чтобы выбрать те, которые следует ждать или продолжать в монолитной архитектуре.

brunofl
источник
-1

Ваша позиция правдоподобна и правильна.

Как убедить окрашенных в шерсти дб наркоманов, хотя это другой вопрос. Я бы сказал, у вас есть два варианта.

  1. Найдите конкретный пример, где БД достигла своих пределов. Например, есть ли у вас «архивные таблицы»? Почему это нормально? Какое максимальное количество заказов в секунду вы можете принять? и т. д. Покажите, что БД не соответствует требованиям, и ваше решение их исправляет.

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

Ewan
источник
1
Я не -1, но для того, чтобы это был хороший ответ, я бы потерял ловушку пункта 2 и остановился бы на том, когда было бы целесообразно требовать нескольких баз данных. Я не думаю, что архивные таблицы обязательно являются антипаттерном в базах данных, которые не поддерживают разбиение. База данных, которую я сейчас использую, содержит около 130 ГБ данных с 26 таблицами> 10M строк, а производительность не является достаточно удаленной, чтобы разделить базу данных; поэтому я очень скептически отношусь и хотел бы услышать, почему это хорошая идея, и когда это необходимо сделать - этот ответ является самым близким, который я видел до сих пор.
Маккотл
Что ж. Я упоминаю архивные таблицы, потому что они портят ограничения FK. это щель в доспехах. расщепление микросервисами - это не размер db, а сохранение микросервисов в отдельности. Если вы не можете выключить его и выбросить, это не микросервис. В отношении пункта 2. ОП упоминает MF, они могут буквально нанять его / мысли, чтобы они пришли и сказали им разделить БД
Ewan
«Если вы не можете выключить и выбросить, это не микросервис». Это верно для самого сервиса, но не обязательно является аргументом, почему сервису нужна собственная база данных. В конечном счете, база данных сама по себе является службой, используемой микросервисом. Микросервис на самом деле не знает и не заботится, находятся ли данные, которые он использует, в отдельной базе данных или в общей базе данных. Вы можете увеличивать или уменьшать количество копий этого микросервиса, и на самом деле ничего не меняется.
Крис Пратт
Лучший аргумент для базы данных на службу - это ограничения на соединение. Использование пула соединений не редкость, поэтому для каждого микросервиса уже требуется несколько подключений к экземпляру базы данных, тогда у вас может быть несколько экземпляров каждого из этих микросервисов, каждый со своими собственными пулами. В конце концов все может прийти в тупик, когда вы просто исчерпаете способность базы данных обрабатывать все соединения, которые она получает.
Крис Пратт