Pull to refresh

Comments 19

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

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

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

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

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

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

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

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

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

Есть сервисы (букинг перелета, букинг отеля, аренда машины), которые занимаются своим доменом проблем и предоставляют 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 «в теме» работы сторонних сервисов?
Sign up to leave a comment.