Nano Hash - криптовалюты, майнинг, программирование

Согласованность БД с микросервисами

Как лучше всего добиться согласованности БД в системах на основе микросервисов?

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

Это супер-красиво и элегантно, но на практике становится немного сложно. Предположим, у вас есть несколько сервисов:

  • интерфейс
  • служба управления заказами
  • услуга программы лояльности

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

Теперь, когда все находится на одном сервере БД / БД, все становится проще, поскольку вы можете запускать все за одну транзакцию: если служба программы лояльности не может записать в БД, мы можем откатить все это обратно.

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

Я очень хочу услышать ваши предложения! .. и заранее спасибо!


  • Такие вещи, как механизмы BPEL или распределенные менеджеры транзакций, могут использоваться для обеспечения конечной согласованности всех систем, которые оркестрируются в рамках бизнес-транзакции. Я написал статью в блоге по адресу: blog.maxant.co .uk / pebble / 2015/08/04 / 1438716480000.html, и если вы работаете в среде Java, существует адаптер JCA, который вы можете использовать здесь: github.com/maxant/genericconnector 05.08.2015

Ответы:


1

Это супер-красиво и элегантно, но на практике становится немного сложно.

На практике это означает, что вам необходимо разработать свои микросервисы таким образом, чтобы обеспечить необходимую бизнес-согласованность при соблюдении правила:

эти службы не могут напрямую подключаться к БД, "принадлежащей" другой службе.

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

Теперь к вашему вопросу:

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

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

Если вы используете .NET, некоторые примеры инфраструктуры, поддерживающей такую ​​надежность, включают NServiceBus и MassTransit. Полное раскрытие - я основатель NServiceBus.

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

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

29.06.2015
  • Очень хорошая запись! На самом деле мы используем то, что вы упомянули (например, идемпотентность, асинхронность) - хотя я думаю, что у меня есть менее простой пример, который мог бы стимулировать разговор. Предположим, что после обработки заказа вам необходимо обновить доступный запас на вашем складе, как вы с этим справитесь? Я предполагаю, что системе управления заказами необходимо записать заказ в БД, а затем снять товар со склада путем HTTP-вызова складской службы - и сказать, что это должно быть очень быстрым / надежным (чтобы люди не добавляли к корзина / покупка товаров, которых действительно нет в наличии). 30.06.2015
  • Компания, вероятно, не хочет / не нуждается в гарантии той последовательности, которую вы описываете для запасов, поскольку они могут быть пополнены, а заказ может быть выполнен позже. 16.07.2015
  • Обратите внимание на сложную часть здесь с баллами лояльности - если обновления баланса обрабатываются с задержкой, клиент может фактически иметь возможность заказать больше товаров, чем у него / нее есть баллы. Я борюсь с подобным сценарием и не нашел хорошего решения для сильной согласованности. Также нашел эту статью Мартина Фаулера, в которой говорится, что высокая согласованность является проблемой для микросервисов: martinfowler .com / article / microservice-trade-offs.html. 28.09.2015
  • @PavelGrushetzky, с которой можно было бы справиться, введя дополнительные правила - если пользователь получает отрицательные баллы лояльности, уведомите их. Если T проходит без сортировки баллов лояльности, сообщите пользователю, что с него будет взиматься плата M на основе некоторого коэффициента конверсии. Эта политика должна быть видна клиентам, когда они используют баллы для покупок. 29.09.2015
  • Возможно, @UdiDahan, но обратите внимание, сколько предположений / предпосылок содержится в этих правилах. Они сразу приходят мне в голову: (1) Это нормально взимать с участников программы лояльности (LPM) реальные деньги, когда их намерение состоит в том, чтобы потратить баллы. (2) С точки зрения бизнеса это нормально, если LPM принимает новые положения и условия. (3) Компания может хранить данные кредитной карты. (4) Каждый LPM имеет определенную кредитную карту или может быть вынужден ввести ее, разместив запрос на погашение. 02.10.2015

  • 2

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

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

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

    1. Во-первых, интерфейс помещает запись в свою базу данных со всеми данными. Назовите это записью внешнего интерфейса.
    2. Интерфейс запрашивает у серверной части управления заказами идентификатор транзакции и передает ему все данные, которые потребуются для выполнения действия. Бэкэнд управления заказами хранит эти данные в промежуточной области, привязывая к ним новый идентификатор транзакции и возвращая его во внешний интерфейс.
    3. Идентификатор транзакции управления заказами хранится как часть записи внешнего интерфейса.
    4. Интерфейс запрашивает у серверной части программы лояльности идентификатор транзакции и передает ему все данные, которые потребуются для выполнения действия. Бэкэнд программы лояльности хранит эти данные в промежуточной области, связывая с ним новый идентификатор транзакции и возвращая его во внешний интерфейс.
    5. Идентификатор транзакции программы лояльности хранится как часть записи внешнего интерфейса.
    6. Интерфейс сообщает серверу управления заказами завершить транзакцию, связанную с идентификатором транзакции, который хранится во внешнем интерфейсе.
    7. Интерфейс сообщает серверу программы лояльности завершить транзакцию, связанную с идентификатором транзакции, который хранится во внешнем интерфейсе.
    8. Интерфейс удаляет свою запись внешнего интерфейса.

    Если это будет реализовано, изменения не обязательно будут атомарными, но они будут в конечном итоге согласованными. Давайте подумаем, где это могло произойти:

    • Если это не удается на первом этапе, данные не изменятся.
    • Если это не удается во втором, третьем, четвертом или пятом, когда система возвращается в оперативный режим, она может сканировать все записи внешнего интерфейса, ища записи без связанного идентификатора транзакции (любого типа). Если он встречает любую такую ​​запись, он может воспроизвести ее, начиная с шага 2. (Если на шаге 3 или 5 произошел сбой, в бэкэндах останутся некоторые заброшенные записи, но они никогда не будут перемещены из промежуточной области, поэтому все хорошо.)
    • В случае сбоя на шестом, седьмом или восьмом шаге, когда система возвращается в режим онлайн, она может искать все записи внешнего интерфейса с заполненными идентификаторами обоих транзакций. Затем он может запросить серверные части, чтобы увидеть состояние этих транзакций - совершенные или незафиксированные. . В зависимости от того, какие из них были совершены, он может возобновиться с соответствующего шага.
    28.06.2015

    3

    Я согласен с тем, что сказал @Udi Dahan. Просто хочу добавить к его ответу.

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

    1) Устранить отказ API программы лояльности. Другими словами, он может сохранять запросы, чтобы они не терялись и могли быть восстановлены (повторно выполнены) в какой-то более поздний момент.

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

    3) Делайте то, что сказал Уди, и ставьте это в хорошую очередь (точнее, шаблон pub / sub). Обычно для этого требуется, чтобы подписчик выполнял одно из двух действий ... либо сохранял запрос перед удалением из очереди (goto 1) - ИЛИ - сначала заимствовал запрос из очереди, а затем, после успешной обработки запроса, получил запрос удален из очереди (это мое предпочтение).

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

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

    29.06.2015

    4

    Даже для распределенных транзакций вы можете попасть в «статус транзакции под сомнением», если один из участников выйдет из строя во время транзакции. Если вы спроектируете службы как идемпотентную операцию, жизнь станет немного проще. Можно писать программы для выполнения бизнес-условий без XA. Пэт Хелланд написал отличную статью по этому поводу под названием «Life Beyond XA». В основном подход состоит в том, чтобы делать как можно меньше предположений об удаленных объектах. Он также проиллюстрировал подход под названием «Открытые вложенные транзакции» (http://www.cidrdb.org/cidr2013/Papers/CIDR13_Paper142.pdf) для моделирования бизнес-процессов. В этом конкретном случае транзакция покупки будет потоком верхнего уровня, а управление лояльностью и заказами - потоками следующего уровня. Уловка состоит в том, чтобы разделить гранулированные сервисы как идемпотентные сервисы с логикой компенсации. Поэтому, если что-то выходит из строя где-либо в потоке, отдельные службы могут это компенсировать. Так, например, если заказ по какой-либо причине не выполняется, лояльность может вычесть баллы, начисленные за эту покупку.

    Другой подход заключается в моделировании с использованием конечной согласованности с использованием CALM или CRDT. Я написал блог, чтобы осветить использование CALM в реальной жизни - http://shripad-agashe.github.io/2015/08/Art-Of-Disorderly-Programming Может быть, это вам поможет.

    29.09.2015
    Новые материалы

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

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

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

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..