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

64

Я недавно прочитал эту прекрасную статью об архитектуре микросервиса: http://www.infoq.com/articles/microservices-intro

В нем говорится, что когда вы загружаете веб-страницу в Amazon, более 100 микросервисов сотрудничают, чтобы обслуживать эту страницу.

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

Я что-то здесь упускаю? Есть ли какая-то другая причина, по которой данные должны читаться только через API?

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

Дэвид
источник
Еще один общий фактор, не упомянутый в ответах, заключается в том, что при записи в базу данных локальное кэширование, даже простое отображение O / R, может привести к устареванию данных при немедленном доступе к базе данных. Если вы подумаете об обходе µservice API по соображениям скорости, вполне возможно, что вы зашли слишком далеко на архитектуру µservice.
Joop Eggen
При разрешении чтения базы данных каждая деталь базы данных становится частью общедоступного API. Я не хотел бы поддерживать совместимость на таком сложном API.
Патрик
Но в этом случае представление просто не становится частью API, по крайней мере, для семантических целей? Это просто вопрос того, что вы называете API, и что это заставляет вас поддерживать. (Обычно слой над базой данных легче поддерживать согласованным.)
lc.
Я согласен, что представление будет просто формой API. Я думаю, что большинство людей, отвечающих на этот вопрос, не читают мою идею об использовании представлений как уровня абстракции. Я понимаю, однако, что сохранение целостности представления о том, что кто-то изменил технологию баз данных, было бы серьезной проблемой, но я готов поспорить, что нам не нужно будет менять нашу технологию баз данных в течение следующих 5 лет. Кроме того, производительность не будет проблемой только для 5 миллионов пользователей. Итак, учитывая наш размер, я благодарен, что пойду за этим решением, хотя ответы здесь, кажется, указывают, что я направляюсь прямо в мир боли.
Дэвид

Ответы:

69

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

Сценарий: вы связываете пару компонентов непосредственно с RDBMS и видите, что один конкретный компонент становится узким местом для производительности, для которого вы можете захотеть денормализовать базу данных, но вы не можете, потому что это затронет все другие компоненты. Вы даже можете понять, что вам лучше использовать хранилище документов или графическую базу данных, чем СУБД. Если данные инкапсулированы небольшим API, у вас есть реальная возможность переопределить указанный API любым удобным для вас способом. Вы можете прозрачно вставлять слои кэша, а что нет.

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

back2dos
источник
1
Это отличный момент! Меня меньше беспокоит то, что Postgres теперь поддерживает и хранилище документов, и RDBMS (без thelolo.com/articles/2014-09-30-postgresql-nosql ). Однако ваша точка зрения остается в силе, и я внимательно ее рассмотрю.
Дэвид
3
@David не должен вызывать у вас меньше беспокойства только потому, что инструмент может что-то делать, но это не значит, что его изменение не сломает много вещей. В этом и заключается смысл разделения - вы можете полностью изменить данные за API, не меняя то, что видит пользователь. Я выступаю в роли администратора баз данных здесь ... до тех пор, пока клиент видит то же самое, вы можете изменять его как угодно.
Бен
1
@ Давид Хотя это интересная новость, она не имеет отношения к описанному мной сценарию. Если вы измените свою схему БД с реляционной на основанную на документе схему, это окажет одинаковое влияние на все те, которые зависят от нее: вам придется переписать все запросы. Существует также кошмар необходимости развертывания всех этих изменений одновременно, чтобы обеспечить совместимость компонентов во всей системе.
back2dos
1
@ Дэвид: Ограничение доступа к нескольким четко определенным представлениям, возможно, означает создание другого API с некоторыми преимуществами, которые приходят с ним. Пока это только просмотры, вы ограничены доступом только для чтения. Наличие компонента, зависящего как от API службы, так и от API представления, делает его очень хрупким. Поэтому, если вы делаете компонент зависимым от представлений, вы заранее определили, что он предназначен только для чтения или требует большого обслуживания. Я чувствую технический долг здесь. Также вы можете захотеть добавить горизонтальное разбиение так, как это не позволяет ваша база данных.
back2dos
2
@ Давид: В долгосрочной перспективе более важно, насколько легко изменить код, а не как легко его написать. Архитектура не говорит «вы не должны писать код таким-то и таким-то образом», она говорит «если вы это сделаете, вы будете страдать от ужасных кошмаров, пытаясь его поддерживать». Если вы говорите о прототипах, то обслуживание не является обязательным требованием. Преуспевать. Прототип должен доказать свою точку зрения как можно проще. Но когда вы пытаетесь интегрировать все проверенные точки в систему, не превращая ее в сизифовские пытки, вызванные самим собой, вам лучше пройти лишнюю милю.
back2dos
55

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

Теперь, если вы идете заглядывать в свою базу данных

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

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

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

itsbruce
источник
4
Обратите внимание, что все вышеперечисленные пункты действительны, даже если вы являетесь единственным разработчиком, работающим над всем проектом. Управление сложным проектом, даже самостоятельно, вызывает все эти проблемы.
Брюс
15

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

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

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

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

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

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

maple_shaft
источник
4

За последние 20 лет я видел несколько больших модульных конструкций баз данных и уже несколько раз видел сценарий, предложенный Дэвидом, где приложения имеют доступ на запись к своей собственной схеме / набору таблиц и доступ на чтение к другой схеме / набор столов. Чаще всего эти данные, к которым приложение / модуль получает доступ только для чтения, могут быть описаны как «основные данные» .

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

Сценарий: вы связываете пару компонентов непосредственно с RDBMS и видите, что один конкретный компонент становится узким местом в производительности

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

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

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

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

Для меня это утверждение просто не правильно. Денормализация - это «аддитивное» изменение, а не «критическое изменение», и ни одно приложение не должно прерваться из-за денормализации.

Единственный способ сломать приложение - это когда код приложения использует что-то вроде «select * ...» и не обрабатывает дополнительный столбец. Для меня это будет ошибка в приложении?

Как денормализация может сломать приложение? Похоже, FUD для меня.

Зависимость схемы:

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

Основные данные

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

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

нормализация

Если 3 дизайнера баз данных займутся разработкой нормализованной схемы БД, они получат одинаковый дизайн. Хорошо, может быть некоторое изменение 4NF / 5NF, но не очень. Более того, есть ряд вопросов, которые дизайнер может задать для проверки модели, чтобы дизайнер мог быть уверен, что они получили 4NF (я слишком оптимистичен? Люди борются с переходом на 4NF?).

Обновление: По 4НФУ здесь я имею в виду все таблицы в схеме должны их высшую нормальной форму до 4НФА (все таблицы получили нормировать соответственно до 4НФА).

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

Процесс нормализации приводит дизайн БД к известному «правильному» дизайну, а отклонения от него должны быть денормализованы для производительности.

  1. Могут быть вариации, основанные на поддерживаемых типах БД (JSON, ARRAY, поддержка Geo-типов и т. Д.)
  2. Некоторые могут утверждать, что вариации основаны на 4NF / 5NF.
  3. Мы исключаем физические изменения (потому что это не имеет значения)
  4. Мы ограничиваем это дизайном OLTP, а не дизайном DW, потому что это схемы, которым мы хотим предоставить доступ только для чтения

Если бы 3 программиста получили проект для реализации (в виде кода), ожидание было бы для 3 разных реализаций (потенциально очень разных).

Для меня потенциально существует вопрос "веры в нормализацию".

Ломать схему изменениями?

Денормализация, добавление столбцов, изменение столбцов для увеличения объема памяти, расширение дизайна новыми таблицами и т. Д. - все это неразрывные изменения, и дизайнеры БД, которые получили 4-ую нормальную форму, будут в этом уверены.

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

Мне было бы интересно услышать случаи нарушения схемы в контексте общих схем только для чтения.

Что важнее и важнее в микросервисе: его API или схема базы данных? API, потому что это его контракт с остальным миром.

Хотя я согласен с этим утверждением, я думаю, что есть важный нюанс, который мы могли бы услышать от Enterprise Architect: «Данные живут вечно» . То есть, хотя API может быть самой важной вещью, данные также довольно важны для предприятия в целом, и они будут важны в течение очень долгого времени.

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

Проблемы с API?

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

What motivates people to desire local read-only access?

Оптимизация API:

У LinkedIn есть интересная презентация (с 2009 года) по вопросу оптимизации их API и почему это важно для них в их масштабе. http://www.slideshare.net/linkedin/building-consistent-restful-apis-in-a-highperformance-environment

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

Если API не обладает той же сложностью, что и LinkedIn, вы можете легко получить сценарии, в которых:

  • API извлекает гораздо больше данных, чем вам нужно (расточительно)
  • Chatty API, где вы должны вызывать API много раз

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

Я подозреваю, что есть множество людей, которые могли бы добавить это как:

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

Этот ответ слишком длинный. Извиняюсь !!

Роб Бигрейв
источник
Добавление столбца обычно ломает приложения. Если у вас есть «зарплата», приложение, которое суммирует все зарплаты, прерывается, когда вводится новый столбец «salary_currency».
Кубанчик
В самом деле? Полагаю, от вашего определения «разрывов» я полагаю. Если приложение находилось в рабочем состоянии и работало, как и ожидалось, без «salary_currency», почему вы считаете это приложение теперь неработающим?
Роб Бигрейв
Приложение работает без ошибок и отображает некоторое число. Но это бесполезно. Когда генеральный директор видит, что сумма зарплат за последний месяц составляет 6 миллионов вместо 50 тысяч (из-за одного нового сотрудника, которому платят в южнокорейских вонах), определение полезного / бесполезного результата не будет обсуждаться много.
Кубанчик
0

Управление состоянием (возможно, база данных) может быть развернуто в контейнере Микросервиса и предоставлено через API. База данных микросервиса не видна другим системам вне контейнера - только API. В качестве альтернативы вы можете использовать другой сервис (например, кеш) для управления состоянием через API. Наличие всех зависимостей Микросервиса (кроме вызовов API для других служб) в одном развертываемом контейнере является ключевым отличием в архитектуре. Если не получится, вернитесь и изучите архитектуру.

Эрик Рох
источник