Сохранение согласованности между агрегатами

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

Представьте, что вы продаете коровье молоко. У вас есть несколько коров, каждая из которых производит определенное количество литров молока в день. Вам нужно иметь службу, которая сможет получить количество молока на складе. Кроме того, вы также сможете заказать молоко. На основании этой информации вы можете создать три совокупности, Cow, Stock а также Order, Всякий раз, когда заказывается определенное количество молока, одним из бизнес-правил является проверка наличия этого количества на складе, а если нет, сразу же сообщите об этом пользователю. Как этого достичь, если два пользователя одновременно выполняют запрос и заказывают 150 литров молока, а доступно всего 130 литров? Моя первая идея заключается в том, что вы можете добиться этого с помощью оптимистической / пессимистической блокировки, но в этом случае один агрегат зависит от другого. Есть ли определенный способ решить эту конкретную проблему, или это просто плохой агрегатный дизайн?

2 ответа

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

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

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

На основании этой информации вы можете создать три агрегата: Корова, Запас и Порядок.

Замечания: Cow это паршивая совокупность - если предположить, что мы говорим о реальном в мире, поедающем травяных коров. Это сущность, да, но это вне влияния модели. Если модель говорит, что корова пуста, а корова говорит, что она полна молока, корова права.

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

Агрегаты - это информационные ресурсы.

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

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

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

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

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

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

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

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

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

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

Просто некоторые мысли:)

Другие вопросы по тегам