Обеспечение согласованности данных между сервисом и монолитом¶
Предположим, что мы извлекли из монолита сервис Kitchen. Из-за этого придется перевести в монолитном коде такие операции как createOrder() и cancelOrder() на повествования, чтобы сущности Ticket и Order остались согласованными.
Однако участие монолита в повествованиях не всегда проходит гладко. Например, повествования должны использовать компенсирующие транзакции для отмены изменений, однако, внедрение компенсирующих транзакций в монолит потребует многочисленных изменений и большого количества времени. Также монолиту, возможно, придется реализовать контрмеры, чтобы справиться с недостаточной изоляцией между повествованиями.
Однако, чаще всего можно спланировать последовательность извлечения сервисов так, чтобы транзакции монолита не было нужды делать компенсируемыми.
Трудности изменения монолита для поддержки компенсируемых транзакций¶
Рассмотрим проблему с компенсирующими транзакциями, которую необходимо решить при извлечении сервиса Kitchen. Это подразумевает разделение сущности Order и создание в сервисе Kitchen сущности Ticket и изменение команд в монолите, включая createOrder().
Монолит реализует createOrder() в виде одной ACID-транзакции:
- Проверить детали заказа.
- Убедиться в том, что клиент может размещать заказы.
- Авторизовать банковскую карту клиента.
- Создать заказ.
Эту транзакцию нужно заменить повествованием:
- В монолите
- Создать заказ с состоянием
APPROVAL_PENDING - Убедиться в том, что клиент может размещать заказы
- Создать заказ с состоянием
- В сервисе
Kitchen- Проверить детали заказа
- Создать заявку с состоянием
CREATE_PENDING
- В монолите
- Авторизовать карту клиента
- изменить состояние заказа на
APPROVED
- В сервисе
Kitchen- Изменить состояние заявки на
AWAITING_ACCEPTANCE
- Изменить состояние заявки на
Сложность реализации этого повествования состоит в том, что первый шаг, на котором создается заказ, должен быть компенсируемым. Сущность Order должна поддерживать семантическую блокировку, сигнализирующую о том, что заказ находится в процессе создания.
Это может потребовать масштабной модификации монолита.
Повествования не всегда требуют от монолита поддержки компенсируемых транзакций¶
Поддержка компенсируемых транзакций нужна только в том случае, когда последующие транзакции монолита могут завершиться неудачно. Если же все транзакции монолита являются либо поворотными, либо повторяемыми, ему не нужно будет ничего компенсировать, и нужно будет внести только небольшие изменения.
Представим, что вместо Kitchen мы извлекаем сервис Order. Тогда повествование createOrder() будет таким:
- Сервис
Order- Создать заказ с состоянием
APPROVAL_PENDING
- Создать заказ с состоянием
- Монолит
- Убедиться в том, что клиент может размещать заказы
- Проверить детали заказа и создать заявку
- Авторизовать банковскую карту клиента
- Сервис
Order- Изменить состояние заказа на
APPROVED
- Изменить состояние заказа на
Здесь транзакция монолита является поворотной.
Планирование извлечения сервисов, чтобы избежать реализации компенсирующих транзакций в монолите¶
Как мы видели, извлечение Kitchen требует реализации в монолите компенсирующих транзакций, а извлечение Order — нет. Следовательно, порядок извлечения сервисов имеет значение. Можно сделать так, чтобы все транзакции в монолите были либо поворотными, либо повторяемыми. Например, если извлечь после сервиса Order сервис Consumer, то это упростит извлечение Kitchen.
После извлечения Consumer команда createOrder() имеет вид:
- Сервис
Order- Создать заказ с состоянием
APPROVAL_PENDING
- Создать заказ с состоянием
- Сервис
Consumer- Убедиться в том, что клиент имеет право размещать заказы
- Монолит
- Проверить детали заказа и создать заявку
- авторизовать карту клиента
- Сервис
Order- Изменить состояние заказа на
APPROVED
- Изменить состояние заказа на
Вслед за Consumer извлекаем сервис Kitchen. Теперь:
- Сервис
Order— создать заказ с состояниемAPPROVAL_PENDING - Сервис
Consumer— убедиться в том, что клиент может размещать заказы. - Сервис
Kitchen— проверить детали заказа и создать заявку с состояниемPENDING - Монолит — авторизовать банковскую карту клиента
- Сервис
Kitchen— изменить состояние заявки наAPPROVED - Сервис
Order— изменить состояние заявки наAPPROVED
Здесь транзакция монолита остается поворотной.
Если теперь продолжить рефакторинг монолита, и извлечь сервис Accounting, то команда createOrder() будет использовать такое повествование:
- Сервис
Order— создать заказ с состояниемAPPROVAL_PENDING - Сервис
Consumer— убедиться в том, что клиент может размещать заказы. - Сервис
Kitchen— проверить детали заказа и создать заявку с состояниемPENDING - Сервис
Accounting— авторизовать банковскую карту клиента - Сервис
Kitchen— изменить состояние заявки наAPPROVED - Сервис
Order— изменить состояние заявки наAPPROVED
Дата создания : 4 августа 2022 г.