Открыть список
Как стать автором
Обновить

Оркестрируемая сага или как построить бизнес-транзакции в сервисах с паттерном database per service

Блог компании Конференции Олега Бунина (Онтико)Блог компании АвитоPostgreSQLАнализ и проектирование системПроектирование и рефакторинг
Всего голосов 44: ↑44 и ↓0 +44
Просмотры24K
Комментарии 19

Комментарии 19

PG Saga сервис является очень ответственным и высоконагруженным звеном, поскольку в реальности он, а не владелец саги, выполняет все запросы. Как вариант, сага может быть реализована компонентом и все шаги выполняются в самом сервисе-инициаторе саги.
В нашей реализации — одно из требований соблюсти 100% консистентность. Гарантию сохранности состояния обеспечивает сервис саг с синхронной репликацией (для исключения потери данных). А у сервиса инициатора саги может быть хранилище, которое способно терять данные при аварии.

В нашей реализации — одно из требований соблюсти 100% консистентность

Так у всех такое требование, зачем иначе то огород городить? :)
Гарантию сохранности состояния обеспечивает сервис саг с синхронной репликацией (для исключения потери данных)

А что мешает компоненту, который отвечает за сагу, использовать хранилище с репликацией?
Мне просто кажется необоснованным введение специального сервиса PG Saga. Кроме того, «общение» инициатора саги с другими сервисами становится более сложным из-за посредника.

Не ясно тогда, чем этот компонент от сервиса саг отличается?
Второй момент у каждого сервиса появляется +1 хранилище.
На мой взгляд — выглядит ещё сложнее

Не ясно тогда, чем этот компонент от сервиса саг отличается?
Он отличается тем, что вы, например, стресс-тестируете «целевые» сервисы, а не сервис саг, на который как раз в вашей реализации и приходится большая наргрузка.
Второй момент у каждого сервиса появляется +1 хранилище.

Так вы ж там про микросервисы писали:
с помощью паттерна Database per service
Почему вдруг тут сложнее? Кроме того, кто запрещает всем компонентам использовать одну БД?
У вас сервис саг должен обновляться при изменении контракта, например, сервиса Биллинга? Один и тот же инстанс сервиса саг может использоваться другими с другими сагами?
Он отличается тем, что вы, например, стресс-тестируете «целевые» сервисы, а не сервис саг, на который как раз в вашей реализации и приходится большая наргрузка
Сервис саг покрыт тестами. Емкость и NFR известны
Database per service
Так вот как раз у сервисов многих хранилище работет в режиме асинхронной репликации
Кроме того, кто запрещает всем компонентам использовать одну БД?
Антипаттерн
У вас сервис саг должен обновляться при изменении контракта, например, сервиса Биллинга?
Создается новый класс саг — который использует новый контракт ( я писал про это выше)
Один и тот же инстанс сервиса саг может использоваться другими с другими сагами?
да

Отличная презентация!

НЛО прилетело и опубликовало эту надпись здесь
1) если Сага не даёт гарантий атомарности и изоляции, то как быть с операциями которые чувствительны к изоляции? Скажем, юзер вполне может купить два товара за 50 $ при балансе в 20.
Проектирование саги ( начинать с резерва денег и проверки баланса в вашем примере)
2) чем это лучше чем NoSql базы (MongoDB или там Cassandra — не суть важно), которые тоже не дают этих гарантий, но с ними хоть мороки меньше — это слой абстракции, а для Саги нужно делать самодельный rollback.
Как я писал выше — если можно без саг — лучше без саги — все должно быть обосновано. На определенном этапе роста вы можете
— упереться в производительность 1 СУБД
— сложная логика и неочевидные зависимости монолита будут очень сильно замедлять доставку изменений в продакшн
НЛО прилетело и опубликовало эту надпись здесь
но ведь если нет изоляции между транзакциями, то баланс может измениться уже после проверки, ведь так? Предположу, что эти случаи как-то детектируются (поправьте меня) и происходит что-то вроде ошибки «оптимистик лока», либо же это обнаруживается тем чекером который спустя 12 часов обнаружит что транзакция прошла некорректно, но вот юзер уже это купил
Да, сагу строим с помощью оптимистичных локов
я пытаюсь понять — в чем отличие от NoSql субд, которые тоже не консистентны и не предоставляют ACID. Можете прокомментировать?
NOSQL субд разные есть — в том числе с ACID :) И части саги (шаги) у нас реализованы в том числе и на NOSQL. Отличие в том, что это архитектурный паттерн, который мы реализовали для бизнес транзакций между микросервисами, написанными на разных языках и с разными хранилищами. А кому-то этот паттерн может понадобится в рамках 1 сервиса и 1 СУБД, как в первоисточнике ftp.cs.princeton.edu/reports/1987/070.pdf (у нас такая потребность тоже была и мы ее реализовали с помощью PgQ и defproc)
ну Сага тоже вроде не такая уж простая
Речь идет о проблемах, связанных с монолитной архитектурой. Многие проекты живут с монолитной архитектурой, не испытывая сложностей и не планируют перехода на микросервисную архитектуру, например.
НЛО прилетело и опубликовало эту надпись здесь
То что я вынес из презентации про Сагу (возможно напутал или додумал что-то). Сага — это набор практик, которые помогают выполнять набор связанных задач. Например, хотим сагу «путешествие», которое невозможно без отеля и перелета. Если хоть одна из задач не выполнилась (кончились номера в отеле), нужно компенсировать уже выполненные задачи (вернуть деньги за авиабилет).

Есть сервисы (букинг перелета, букинг отеля, аренда машины), которые занимаются своим доменом проблем и предоставляют API для общения. Эти сервисы скорее всего не знают о существование друг-друга (им незачем). У каждого сервиса есть свой storage (например Postgres), никто из сервисов не может ходить напрямую в чужой storage, общение только через API. Внутри этих сервисов используются DB транзакции и блокировки (e.g., select for update) когда обновляются «внутреннее» представление данных (всякие таблицы booking).

Координатор Саги — это какой-нибудь сервис, который знает про все другие сервисы и знает как запускать саги (какие API сервисов дернуть чтобы получилось «путешествие» и как компенсировать пользователей, если что-то пошло не так). У координатора есть свой storage, где записаны все шаги.

В распределенных сервисах постоянно что-то идет не так — запросы не долетают, либо долетают но мы не знаем об этом, пришло 10 запросов из-за retry и так далее. Посему API сервисов должны быть спроектированы следующим образом:
— дубликаты запросов должны игнорироваться (клиент передает уникальный токен для дедупликации на стороне сервиса)
— сервис должен предоставить возможность компенсировать «затрату», например, если списали деньги, послать платеж пользователю на ту же сумму (не нужно «отменять» предыдущий платеж, так как событие уже произошло и желательно зафиксировать это в случае диспутов). Компенсирующий API запрос тоже должен быть идемпотентным.
— результат 10ти дубликатов API запросов на букинг отеля и 100500 компенсаций этого действия (все запросы пришли в произвольной последовательности с разными задержками, например в 1 день) должны привести к одному результату (забукали один раз и отменили букинг один раз)
На какую нагрузку рассчитан движок PGSaga? Сколько «шагов» в секунду на сервер?
Как определяется логика шага для executor — это просто какой-то RCP вызов или что-то сложнее?
На какую нагрузку рассчитан движок PGSaga? Сколько «шагов» в секунду на сервер?
тут есть несколько блоков
— api масштабируется линейно
— executor
— хранилище
— и др
В нашей текущей реализации на 1 инстансе хранилища мы выполняем ~ 3000 шагов в секунду, можно больше в несколько раз, но мы оставляем запас на случай внезапного роста нагрузки.
Как определяется логика шага для executor — это просто какой-то RCP вызов или что-то сложнее?
Просто вызов API
Ага, т.е. столько же, сколько у меня на персистентных акторах получалось (для решения примерно тех же задач).
Хотя пока мне кажется, что акторная модель для описания бизнес-транзакций более удобна. Ну и вместо блокировок можно использовать актор-на-блокируемый объект.
Скажите, пожалуйста, а в каких терминах описывается сага при регистрации в сервисе саг? Там какой то понятный executor'у и compensator'у мета-язык или, грубо говоря, просто параметры для POST/PUT/DELETE запросов к другим сервисам? Насколько executor «в теме» работы сторонних сервисов?
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Информация

Дата основания
Местоположение
Россия
Сайт
www.ontico.ru
Численность
11–30 человек
Дата регистрации

Блог на Хабре