Одна из основных проблем, с которыми я столкнулся, возникает в системе с микросервисами, это то, как транзакции работают, когда они охватывают разные сервисы. В нашей собственной архитектуре мы использовали распределенные транзакции для решения этой проблемы, но они имеют свои собственные проблемы. Особенно тупики были болью до сих пор.
Похоже, что другой вариант - это какой-то специальный менеджер транзакций, который знает потоки в вашей системе и позаботится о ваших откатах как о фоновом процессе, охватывающем всю вашу систему (поэтому он сообщит другим сервисам об откате). и если они не работают, сообщите об этом позже).
Есть ли другой, принятый вариант? Оба из них, кажется, имеют свои недостатки. Первый может вызвать взаимные блокировки и множество других проблем, второй может привести к несогласованности данных. Есть ли лучшие варианты?
источник
Ответы:
Обычный подход состоит в том, чтобы максимально изолировать эти микросервисы - рассматривать их как отдельные элементы. Затем транзакции могут быть разработаны в контексте службы в целом (то есть не являются частью обычных транзакций БД, хотя вы все равно можете иметь транзакции БД внутри службы).
Подумайте, как происходят транзакции и какой смысл имеет смысл для ваших сервисов, тогда вы можете реализовать механизм отката, который отменяет исходную операцию, или двухфазную систему фиксации, которая резервирует исходную операцию до тех пор, пока ей не будет предложено зафиксировать транзакцию по-настоящему. Конечно, обе эти системы означают, что вы внедряете свою собственную, но тогда вы уже внедряете свои микросервисы.
Финансовые службы постоянно делают подобные вещи - если я хочу перевести деньги из моего банка в ваш банк, не будет ни одной транзакции, как у вас в БД. Вы не знаете, какие системы работают в любом банке, поэтому должны эффективно относиться к каждой из них, как к вашим микросервисам. В этом случае мой банк переместил бы мои деньги со своего счета на текущий счет, а затем сказал бы вашему банку, что у них есть деньги, если при отправке произошел сбой, мой банк возместит мой счет деньгами, которые они пытались отправить.
источник
Я думаю, что стандартная мудрость заключается в том, чтобы транзакции не пересекали границы микросервиса Если какой-либо конкретный набор данных действительно должен быть атомарно согласован с другим, эти две вещи принадлежат друг другу.
Это одна из причин, по которой очень сложно разделить систему на сервисы, пока вы полностью не разработаете ее. Что в современном мире, вероятно, означает написано это ...
источник
Я думаю, что если согласованность является сильным требованием в вашем приложении, вы должны спросить себя, являются ли микросервисы лучшим подходом. Как говорит Мартин Фаулер :
Но, возможно, в вашем случае, вы можете пожертвовать Последовательность в pos доступности
Однако я также спрашиваю себя, существует ли стратегия для распределенных транзакций в микросервисах, но, возможно, цена слишком высока. Я хотел дать вам свои два цента с всегда превосходной статьей Мартина Фаулера и теоремой CAP .
источник
Как предлагается, по крайней мере, в одном из ответов здесь, но также и в других местах в Интернете, можно спроектировать один микросервис, который сохраняет сущности вместе в рамках обычной транзакции, если вам требуется согласованность между двумя сущностями.
Но в то же время у вас вполне может возникнуть ситуация, когда сущности на самом деле не принадлежат одному и тому же микросервису, например, записи продаж и записи заказов (когда вы заказываете что-то для выполнения продажи). В таких случаях вам может потребоваться способ обеспечения согласованности между двумя микроуслугами.
Традиционно распределенные транзакции использовались и, по моему опыту, они работают хорошо, пока не масштабируются до размера, когда блокировка становится проблемой. Вы можете ослабить блокировку, чтобы действительно только релевантные ресурсы (например, продаваемый предмет) были «заблокированы» с помощью изменения состояния, но именно здесь оно начинает усложняться, потому что вы входите на территорию, где вам нужно построить все логика сделать это самостоятельно, а не иметь, скажем, базу данных обрабатывать это для вас.
Я работал с компаниями, которые пошли по пути создания собственной структуры транзакций для решения этой сложной проблемы, но я не рекомендую ее, потому что это дорого и требует времени для созревания.
Есть продукты, которые могут быть прикреплены к вашей системе, которые заботятся о согласованности. Хорошим примером является механизм бизнес-процессов, который, как правило, в конечном итоге обрабатывает последовательность и использует компенсацию. Другие продукты работают аналогичным образом. Как правило, у вас есть уровень программного обеспечения рядом с клиентом (-ами), который имеет дело с согласованностью и транзакциями и вызывает (микро) сервисы для выполнения фактической бизнес-обработки . Одним из таких продуктов является универсальный JCA-коннектор, который можно использовать с решениями Java EE (для прозрачности: я автор). См. Http://blog.maxant.co.uk/pebble/2015/08/04/1438716480000.html для более подробной информации и более глубокого обсуждения вопросов, поднятых здесь.
Другой способ обработки транзакций и согласованности состоит в том, чтобы превратить вызов микросервиса в вызов чего-либо транзакционного, например очереди сообщений. Возьмите приведенный выше пример записи о продажах / записи заказов - вы можете просто позволить микросервису продаж отправить сообщение в систему заказов, которая фиксируется в той же транзакции, которая записывает продажу в базу данных. Результатом является асинхронное решение, которое очень хорошо масштабируется . Используя такие технологии, как веб-сокеты, вы даже можете обойти проблему блокировки, которая часто связана с расширением асинхронных решений. Дополнительные идеи о таких шаблонах см. В другой моей статье: http://blog.maxant.co.uk/pebble/2015/08/11/1439322480000.html .
Какое бы решение вы ни выбрали, важно признать, что только небольшая часть вашей системы будет писать вещи, которые должны быть согласованными - большая часть доступа, вероятно, будет доступна только для чтения. По этой причине встраивайте управление транзакциями только в соответствующие части системы, чтобы оно могло хорошо масштабироваться.
источник
В микросервисах есть три способа достижения согласованности между diff. Сервисы:
Оркестровка - один процесс, который управляет транзакцией и откатом между службами.
Хореография - Сервис передает сообщения между собой и, наконец, достигает согласованного состояния.
Гибрид - смешивание двух выше.
Для полного чтения перейдите по ссылке: https://medium.com/capital-one-developers/microservices-when-to-react-vs-orchestrate-c6b18308a14c
источник
Есть много решений, которые компрометируют больше, чем мне удобно. Конечно, если ваш вариант использования сложный, такой как перемещение денег между различными банками, более приятные альтернативы могут быть невозможны. Но давайте посмотрим, что мы можем сделать в обычном сценарии, когда использование микросервисов мешает нашим потенциальным транзакциям базы данных.
Вариант 1. Избегайте необходимости транзакций, если это возможно
Очевидный и упомянутый ранее, но идеальный, если мы можем справиться с этим. Действительно ли компоненты принадлежат одному и тому же микросервису? Или мы можем изменить систему (ы) так, чтобы транзакция стала ненужной? Возможно, принятие не транзакционности - самая доступная жертва.
Вариант 2: использовать очередь
Если есть достаточная уверенность в том, что другой сервис преуспеет в том, что мы хотим, мы можем вызвать его через некоторую форму очереди. Элемент в очереди не будет забран до позже, но мы можем убедиться, что элемент в очереди .
Например, скажем, что мы хотим вставить объект и отправить электронное письмо как одну транзакцию. Вместо того, чтобы вызывать почтовый сервер, мы ставим электронную почту в таблицу.
Очевидным недостатком является то, что нескольким микросервисам потребуется доступ к одной и той же таблице.
Вариант 3: выполняйте внешнюю работу последним, непосредственно перед завершением транзакции
Этот подход основывается на предположении, что совершить транзакцию очень вряд ли удастся.
Если запросы не выполняются, внешний вызов еще не состоялся. В случае сбоя внешнего вызова транзакция никогда не фиксируется.
Этот подход имеет ограничения, заключающиеся в том, что мы можем сделать только один внешний вызов, и он должен быть выполнен последним (то есть мы не можем использовать его результат в наших запросах).
Вариант 4: создать вещи в состоянии ожидания
Как указывалось здесь , мы можем иметь несколько микросервисов для создания разных компонентов, каждый в состоянии ожидания, без транзакций.
Любая проверка выполняется, но в определенном состоянии ничего не создается. После того, как все было успешно создано, каждый компонент активируется. Обычно эта операция настолько проста, и вероятность того, что что-то пойдет не так, настолько мала, что мы можем даже предпочесть выполнить активацию без транзакций.
Наибольшим недостатком, вероятно, является то, что мы должны учитывать существование ожидающих пунктов. Любой выбранный запрос должен учитывать, следует ли включать ожидающие данные. Большинство должно игнорировать это. А обновления это совсем другая история.
Вариант 5: разрешить микросервису поделиться своим запросом
Ни один из других вариантов не сделает это за вас? Тогда давайте неортодоксально .
В зависимости от компании это может быть неприемлемо. Я знаю. Это неортодоксально. Если это не приемлемо, идите другим путем. Но если это соответствует вашей ситуации, это решает проблему просто и мощно. Это может быть просто самый приемлемый компромисс.
Существует способ превратить запросы из нескольких микросервисов в простую транзакцию с одной базой данных.
Верните запрос, а не выполняйте его.
В сети каждый микросервис должен иметь возможность доступа к каждой базе данных. Имейте это в виду, также в отношении будущего масштабирования.
Если базы данных, участвующие в транзакции, находятся на одном сервере, это будет обычная транзакция. Если они находятся на разных серверах, это будет распределенная транзакция. Код один и тот же независимо.
Мы получаем запрос, включая его тип подключения, его параметры и строку подключения. Мы можем обернуть его в аккуратный исполняемый класс Command, оставляя поток читаемым: вызов microservice приводит к команде, которую мы выполняем, как часть нашей транзакции.
Строка подключения - это то, что дает нам исходный микросервис, поэтому для всех намерений и целей этот запрос все еще считается выполненным этим микросервисом. Мы просто физически направляем его через микросервис клиента. Это имеет значение? Ну, это позволяет нам поместить его в ту же транзакцию с другим запросом.
Если компромисс приемлем, такой подход дает нам прямую транзакционность монолитного приложения в микросервисной архитектуре.
источник
Я бы начал с разложения проблемного пространства - определения границ вашего сервиса . Если все сделано правильно, вам никогда не понадобятся транзакции между службами.
Различные службы имеют свои собственные данные, поведение, мотивационные силы, правительство, бизнес-правила и т. Д. Хороший старт - перечислить возможности высокого уровня, которые есть у вашего предприятия. Например, маркетинг, продажи, бухгалтерия, поддержка. Другой отправной точкой является организационная структура, но имейте в виду, что есть предостережение - по некоторым причинам (например, политическим) это может быть не оптимальная схема декомпозиции бизнеса. Более строгим подходом является анализ цепочки создания стоимости . Помните, что ваши услуги могут включать людей, это не строго программное обеспечение. Службы должны общаться друг с другом через события .
Следующим шагом является создание этих услуг. В результате вы получаете все еще относительно независимые агрегаты . Они представляют единицу согласованности. Другими словами, их внутренности должны быть последовательными и кислотными. Агрегаты общаются друг с другом через события.
Если вы считаете, что ваш домен сначала требует согласованности, подумайте еще раз. Ни одна из больших и критически важных систем не создается с учетом этого. Все они распределены и в конечном итоге согласованы. Проверьте классическую статью Пэт Хелланд .
Вот несколько практических советов о том, как построить распределенную систему.
источник