Русский
Русский
English
Статистика
Реклама

Разложение монолита Декомпозиция БД (часть 2)

Эта статья является заключительным конспектом книги От монолита к микросервисам. Материал статьи посвящен декомпозиции БД во время процесса разложения монолита на микросервисы.

Извлечение микрослужбы не делается до техпор, пока код приложения не будет работать в его собственной службе, а данные,которыми он управляет, не будут извлечены в его собственную логически изолированную БД. Однако в какой последовательности извлечения должны выполняться?

Есть несколько вариантов:

  • Сначала выделить БД, а затем код.

  • Сначала выделить код, а затем БД.

  • Выделить сразу все.

У каждого варианта есть свои плюсы и минусы. Далее будут рассмотрены эти варианты.

Сначала выделить БД

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

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

Одна БД на один ограниченный контекст

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

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

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

Сначала выделить код

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

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

Шаблон: Монолит как слой доступа к данным

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

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

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

Рис. 2 - Использование API Сотрудники для выявления контура службы Сотрудники, которая должна быть выделена из монолита.Рис. 2 - Использование API Сотрудники для выявления контура службы Сотрудники, которая должна быть выделена из монолита.

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

Выделить БД и код вместе

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

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

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

Шаблон: Разложить таблицу

Бывает ситуация, когда данные в одной таблице нуждаются в разделение для двух и более микрослужб. На рис. 3 видим одну совместную таблицу Товарная позиция, в которой хранится информация для каталога и склада.

Рис. 3 - Одна таблица, соединяющая в себе два выделяемых ограниченных контекста.Рис. 3 - Одна таблица, соединяющая в себе два выделяемых ограниченных контекста.

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

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

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

Это означает, что после выделения служб новая служба Финансы будет нуждаться в вызове службы для обновления этого статуса, как мы видим на рис. 4.

Рис. 4 - Новая служба "Финансы" должна совершать вызовы службы для приостановки клиента.Рис. 4 - Новая служба "Финансы" должна совершать вызовы службы для приостановки клиента.

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

Шаблон: Перенос связи по внешнему ключу в код

Допустим мы решили извлечь службу Каталог, которая может управлять и предоставлять информацию об исполнителях, треках и альбомах. В настоящее время каталожный программный код внутри монолита хранит информацию о компакт-дисках в таблице Альбомы. В таблице Приходно-расходный регистр хранится информация о продажах (рис. 5). Таблица Приходно-расходный регистр просто регистрирует сумму за компакт-диск, вместе с идентификатором, который ссылается на проданную товарнуюпозицию. Идентификатор в примере называется SKU.

Рис. 5 Связь по внешнему ключу.Рис. 5 Связь по внешнему ключу.

В конце каждого месяца нужно составлять отчет с описанием самыхпродаваемых компакт-дисков. Таблица Приходно-расходный регистр помогаетнам понять, копий какого артикула продано больше всего, но информация об этомартикуле находится в таблице Альбомы. Для отчетности нужен запрос к БД, инициированный финансовым кодом, который должен присоединить информацию из таблицы Приходно-расходный регистр к таблице Альбомы, как показано на рис. 5. В итоге, имеется связь по внешнему ключу между таблицами.

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

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

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

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

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

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

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

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

Транзакции

Возможность вносить изменения в БД одной транзакцией намного облегчит разработку и сопровождение. Мы полагаемся на БД в том, что она обеспечивает безопасность и согласованность данных, оставляя нам беспокойство о другихвещах. Но при разделении данных по разным БД теряем выгоду от использования транзакции применительно к изменениям.

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

  • Атомарность (atomicity) - обеспечивает, чтобы все операции, завершаемые в рамкахтранзакции, либо все завершались успешно, либо все завершались безуспешно.

  • Согласованность (consistency) - при внесении изменений в БД обеспечивает,чтобы она оставалась в допустимом, согласованном состоянии.

  • Изоляция (isolation) - позволяет нескольким транзакциям работать одновременно без какого-либо вмешательства.

  • Долговечность (durability) - обеспечивает, чтобы после завершения транзакции мы былиуверены, что данные не будут потеряны в случае системного сбоя.

Мы по-прежнему можем использовать транзакциив стиле ACID, когда разбиваем БД, но объем этих транзакций уменьшается, как и их полезность. Предположим, мы отслеживаем процесс, связанный с подключением нового клиента к системе. В конце процесса предусматривается изменение статуса клиента с pending на verified. После завершения регистрации,мы хотим удалить соответствующую строку из таблицы Ожидающие регистрации. С одной БД это делается в рамках одной транзакции ACID либо обе новые строки записываются, либо ни одна из них не записывается. Однако если данные находятся в различных БД, то существует две транзакции, каждая из которых может сработать либо не сработать независимо от другой.

Рис. 6 Изменения в рамках двух разных транзакций.Рис. 6 Изменения в рамках двух разных транзакций.

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

Тогда что еще можно сделать? Первый вариант вообще не разбивать данные. Если у вас есть фрагменты состояния, которыми хотите управлять по-настоящему атомарным и согласованным способом, и не можете решить вопрос, как разумно получить этихарактеристики без транзакции в стиле ACID, то оставьте это состояние в однойБД и сохраните функциональность, которая управляет этим состояниемв одной службе (или в монолите)

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

Саги

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

Cага не дает нам атомарности в терминах АСID, к которой мы привыкли с обычной транзакцией базы данных. Поскольку мы разбиваем бизнес-процесс на отдельные транзакции, у нас нет атомарности на уровне самой саги. У нас есть атомарность для каждой "под-транзакции", поскольку каждая из них может относиться к АСID-транзакционному изменению, если это необходимо. Но вот что сага нам дает, так это достаточно информации для выяснения состояния, в котором она находится.

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

Рис. 7 - Пример потока исполнения заказа наряду со службами,ответственными за проведение операции.Рис. 7 - Пример потока исполнения заказа наряду со службами,ответственными за проведение операции.

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

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

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

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

Рис. 8 Запуск отката всей саги.Рис. 8 Запуск отката всей саги.

Реализация саг

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

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

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

Рис. 9 - Пример того, как оркестрированная сага используетсядля реализации процесса исполнения заказа.Рис. 9 - Пример того, как оркестрированная сага используетсядля реализации процесса исполнения заказа.

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

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

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

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

Рис. 10 - Пример саги на основе хореографии для реализации исполнения заказа.Рис. 10 - Пример саги на основе хореографии для реализации исполнения заказа.

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

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

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

Вывод

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

Ссылки на все части

Источник: habr.com
К списку статей
Опубликовано: 28.03.2021 10:07:00
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Программирование

Анализ и проектирование систем

Проектирование и рефакторинг

Микросервисы

Проектирование систем

Архитектура приложений

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru