А что из себя представляет процесс подготовки данных транзакции в 2pc паттерне? Какой механизм позволяет нам узнать будут данные failed или success? Если есть возможность дождаться ответа от prepare транзакций, почему мы не можем так же дождаться ответа от обычной транзакции, и в зависимости от её ответа выполнять или не выполнять следующую транзакцию? Ответьте, пожалуйста, если найдется время)
Вся подготовка - это блокировка на запись ресурсов которые будут меняться. Сервис денег блокирует 20р, сервис заказов блокирует заказанный товар. Так что конкурирующие процессы эти ресурсы не смогут использовать. Когда блокировка всех русурсов участвующих в покупке успешна - запускаем вторую фазу - списание. А в обычной транзакции, однофазной, ты когда деньги списываешь - еще не знаеешь успешно ли пройдет создание заказа из сервиса заказов или нет. Ты списал 20р и разблокировал счет, а потом что делать если заказ не создался??? Хз. Ну вот SAGA и придумана для создания механизма как вернуть 20р из-за несозданного заказа, чтобы можно было не держать блокировку
Так, а что если в двухфазном комитете обе транзакции 'подготовились' успешно, но одна упала при коммите? Или с одной из бд потерялась связь? Этот вариант у вас не рассмотрен.
У меня вопрос по поводу saga. если я запустил первую транзакцию первый микросервис сделал комит в бд другаю транзакция прочитала эти данные а потом первая транзакция сделала ролбек получается что вторая транзкация продолжает роботу с не существующими данными как это фиксить возможно ли залочить те строчки которые обновила первая транзакция?
Разве SAGA требует эвентов, и там же их две..В целом можно залочить ресурсы в базе без блокировок просто через state машину дополнитетльное поле статусов.
Что делать с ситуацией когда сначала выбираются данные из базы и далее на их основе вычисляется некоторая бизнес логика, которая затем сохраняется в базу. Может быть ситуация, когда первый поток уже выбрал данные из базы, затем второй поток эти данные изменил, далее произошло событие об изменении, после чего первый поток продолжает вычислять бизнес-логику уже на основе неактуальных данных. Проблема из-за отсутствия изолированности, но тут мы даже компенсацию сделать не можем, так как событие об изменении приходит раньше, чем первый поток закончит свою работу.
это должно решаться уровнем изоляции БД "repeatable read" "...просмотр с «repeatable read» удерживает блокировки каждой затронутой строки до окончания транзакции. На всём протяжении транзакции заблокированными могут оказаться даже некоторые строки, которые не соответствуют выборке в результате запроса. Такое блокирование гарантирует, что затронутые запросом строки не будут изменены или удалены в параллельном сеансе, пока текущая транзакция не будет завершена (независимо от того, будет ли она зафиксирована или произойдёт её откат). Эти блокировки не защищают от изменения или удаления те строки, которые еще не были охвачены просмотром, и не препятствуют вставке новых строк межу уже заблокированными строками."
а если в 2pc на этапе коммита мы должны уже финально снять сумму - но снятие суммы это обращение к стороннему сервису - например апи банка и все упало - то что в этом случаи?
А можно приболтать бизнес чтобы распределенных транзакций не было) Тот случай когда софт скилы эффективнее любого паттерна:) Но конечно не всегда такое возможно)
@@IvanFedulov Нужно найти тех людей от которых зависят твои тех решения. Например это может быть Продуктовнер, Аналитик, Системный аналитик, иногда разработчики (например из другой команды). Самое сложное здесь это придумать альтернативное бизнес решение которое будет 1) Без распределенных транзакций 2) Будет простым либо его сложность будет приемлемой. Вообще если подняться на уровень выше то это глобальная идея "Не создавать избыточной сложности" (Его еще называют KISS) и это конечно не только про распределенные транзакции. Будничный пример: Аналитик задизайнил ui. Но есть проблема данные с ui берутся из разных таблиц, и их DDL не оптимален - запрос сложный и медленный. Как делают мидлы? Они решают в лоб и пытаются выжить из sql все что можно - едят кактус. А делают синьеры ? Идут к аналитикам/продактам и предлагают свое решение. Скорее всего их это не устроит. Но тут важно донести почему "нет" и чем это "плохо". Зародить у них мысль о альтернативе. Бывают и позитивные примеры когда Аналитик говорит а так и правда лучше. И вы идете и пишете простой sql за 15 минут.
@@IvanFedulov Не совсем так. Тебе не нужно в прямом смысле подводить. По сути это переосмысление решения задачи, как техническое так и бизнесовое. Тебе нужно найти человека в команде от кого зависит твое техническое решение. Это может быть аналитик, разработчик (в том числе из другой команды), владелец продукта. Вы садитесь с этими людьми и придумываете фичу заново так чтобы она была проще и без распределенных транзакций. Приведу пример правда не про распределенные транзакции. У вас есть ui - данные для него берутся из двух таблиц. Структура таблиц такова что итоговый sql запрос получается а) Сложным для понимания б) медленным. Вы идете к владельцу продукта, и предлагаете разбить ui на два - на выходе получается два простых запроса. Вообщем это творческий путь. Волшебной таблетки здесь нет. В этом и состоит работа Senior разработчика на проекте - работать со сложностью - уменьшать ее.
Спасибо за доклад. Разве для 2PC нельзя применить вариант снятия 20 рублей с баланса пользователя на стадии prepare? Чтобы не делать блокировку баланса для других транзакций
Нельзя. Вот представь, ситуацию, когда 20 р должны не сниматься а поступить на р/счет. Изначально на р/счету 0 р. Если первая трансакция еще не завершена, а вторая уже снимает эти 20 р за покупку какого-то товара и заканчивается успешно. Потом в первой происходит откат , а денег на р/счету уже нет
@@krasser650да в 2pc (которая по факту есть - пессимистический режим блокировок) так и нельзя. А вот в SAGA (которая по факту есть - оптимистический режим блокировок) - можно, т.к. там между первым событием и событием компенсации - баланс не заблокирован - и паралельные транзакции легко могут загнать в минус баланс. Для того и существуют 2 разных механизма, чтобы можно было выбрать - медленно, но надежно, или быстро - но с артефактами неконсистентности
У нас чуть ли не вся система на PLSQL написана. Позволяет добиваться высокой скорости при обеспечении полноценного ACID. Для финансовых систем это важно. При этом это всё равно получается дикий монолит с характерными проблемами. Вот как раз и рассматриваю варианты переноса части логики в микросервисы, но самой большой проблемой сейчас является решение вопроса согласованного чтения. Кроме того, для разных операций нужно обеспечивать быстродействие разного характера: в одном случае быстродействие потоковой обработки событий, в другом: быстродействие одной длинной распределённой, но чувствительной транзакции.
Микросервисы - модно, но порождает головную боль, монолит - классика.. Этот спор технологий разрешит прорыв в переходе к новым сетевым протоколам и новые технологии передачи данных по кабелю.. разумеется в пользу монолита
Не обманывайте людей. В патерне Saga нет транзакции. Не нужно делать подмену понятий типа сказав "локальная транзакция". Почитайте что такое транзакция. Честно было бы сказать что в Sega вы отказываетесь от транзакции и в случае не удачи, пытаетесь восстановить в обратном порядке данные, в случае не сложных систем вы будете иметь редко проблемы, а в сложных..... В 2pc есть свои нюансы, но это транзакция, в Sega ее нет, и тот кто решит это использовать должен об этом знать.
Сама сага состоит из цепочки локальных для каждого микросервиса транзакций. Внутри одного сервиса это именно обычная транзакция. Но между-сервисами сага ведёт себя как начальник: сервис А успешно выполнил транзу? Ок кидаю событие "успех" тогда сервис Б может приступить к своей локальной транзакции. Если она неуспешна - сага создаст событие сервис-Б-ошибка по которому сага запустит откат транзакции на сервис-А.
транзакция - это логическая сущность. Набор операций которые должны быть выполненны или все сразу или ниодна. Можно из без всякой бд создать транзакционный самописный механизм. В БД они просто есть всегда и из коробки
Для 2pc: транзакционные вещи не должны выноситься в 2 микросервиса. Это не разный контекст, это один контекст. Всего должно было быть 3 микросервиса: тот, который про заказы знает, тот который про бабло знает и тот который считает заказы с баблом. Так вот запрос отправляется на 3 микросервис с транзакционной базой данных. Никаких распределённых транзакций. И когда всё ок, то два других микросервиса уменьшают кол-во продуктов у себя на основе данных их общего микросервиса с транзакциями, вычитают деньги. Т.е. по сути это 2 микросервиса на чтение и один на запись. И базы данных тут 2х видо: одна реляционная, и две nosql. Если же у вас сделано так, как в видео, то вы на уровне проектирования неправильно определили границы контекста (частая проблема, при отсутствии опыта DDD). Не всегда контекст "заказов" это один сервис, контекст "счета" второй.
Так тут же нет контекста "счета" или это подобласть сервиса Order. кошелек пользователя и заказы - такое разделение выглядит более чем правильно или я не понял ваш комментарий.
@@ivani3237 обычно чтение данных происходит гораздо чаще, чем запись. Поэтому разумно вынести отдельно часть, которая записывает, чтобы ее не дергали с чтением. И две части, которые позволяют читать.
9:00 при подготовке понятно, а если при отправке команды commit один сервис упал и не закоммитил, как второй откатывать? 16:05 а что если мы упали на компенсационной транзакции и не смогли откатить?
После того, как все успешно сделали prepare и оркестратор (или как его там называют) начинает коммит на всех базах, пути назад нет. Если одна база не успела закоммитить и упала, то после рестарта та транзакция будет висеть, пока не дождется подтверждения коммита.
Если кому интересно откуда пошло название saga, то ответ есть на стековерфлоу. Это просто от слова "сага" - как цепь взаимосвязанных событий.
Да согласен! Консистентность данных это большая головная боль разрабов. особенно где быстро надо.
гениальное видео, спасибо огромное
Отлично объяснили тему. Огромное спасибо)
Отличный материал! Лайк и подписка!
Спасибо!)
соглашусь, отличное обзорное видео
Спасибо. Наглядно объяснил, как работает 2pc
Очень неплохо, благодарю.
Спасибо тебе! Очень доступно
Спасибо за видео.Коммент в поддержку!
А что из себя представляет процесс подготовки данных транзакции в 2pc паттерне? Какой механизм позволяет нам узнать будут данные failed или success? Если есть возможность дождаться ответа от prepare транзакций, почему мы не можем так же дождаться ответа от обычной транзакции, и в зависимости от её ответа выполнять или не выполнять следующую транзакцию?
Ответьте, пожалуйста, если найдется время)
Вся подготовка - это блокировка на запись ресурсов которые будут меняться. Сервис денег блокирует 20р, сервис заказов блокирует заказанный товар. Так что конкурирующие процессы эти ресурсы не смогут использовать. Когда блокировка всех русурсов участвующих в покупке успешна - запускаем вторую фазу - списание. А в обычной транзакции, однофазной, ты когда деньги списываешь - еще не знаеешь успешно ли пройдет создание заказа из сервиса заказов или нет. Ты списал 20р и разблокировал счет, а потом что делать если заказ не создался??? Хз. Ну вот SAGA и придумана для создания механизма как вернуть 20р из-за несозданного заказа, чтобы можно было не держать блокировку
Спасибо, очень полезное видео 👍
очень понятно объяснил
при 2pc можно блокировать не изменение значения поля, а блокировать некий неснижаемый остаток, разрешая менять его другим запросам
ну для неуникальных объектов типа денег - так и делают. Для уникальных - типа билета на конкретное место в поезде - блокируют конкретный объект
Спасибо!
Так, а что если в двухфазном комитете обе транзакции 'подготовились' успешно, но одна упала при коммите? Или с одной из бд потерялась связь? Этот вариант у вас не рассмотрен.
при ошибке в любой фазе надо откат делать
Это почему 2pc не работает в общем случае.
@@владимирсенцов-р1ю 2PC вообще не работает ни в каком случае так как на даёт абсолютно никаких гарантий и не решает проблем.
Здравствуйте. Народ не подскажите где можно найти нормальный проект(Saga pattern вместе с Spring boot)? Везде объяснения, но не могу найти с кодом.
У меня вопрос по поводу saga.
если я запустил первую транзакцию первый микросервис сделал комит в бд другаю транзакция прочитала эти данные а потом первая транзакция сделала ролбек получается что вторая транзкация продолжает роботу с не существующими данными как это фиксить возможно ли залочить те строчки которые обновила первая транзакция?
А если в 2pc не сработал abort()?
Или commit() одной из транзакций… также будет рассинхрон
если не сработал abort то надо городить отдельно логику которая это учтет, в самом шаблоне 2рс ответа нет на эту ситуацию.
Класс
Разве SAGA требует эвентов, и там же их две..В целом можно залочить ресурсы в базе без блокировок просто через state машину дополнитетльное поле статусов.
Музыка лишняя
норм
возможно, тише но норм.
Что делать с ситуацией когда сначала выбираются данные из базы и далее на их основе вычисляется некоторая бизнес логика, которая затем сохраняется в базу. Может быть ситуация, когда первый поток уже выбрал данные из базы, затем второй поток эти данные изменил, далее произошло событие об изменении, после чего первый поток продолжает вычислять бизнес-логику уже на основе неактуальных данных. Проблема из-за отсутствия изолированности, но тут мы даже компенсацию сделать не можем, так как событие об изменении приходит раньше, чем первый поток закончит свою работу.
это должно решаться уровнем изоляции БД "repeatable read"
"...просмотр с «repeatable read» удерживает блокировки каждой затронутой строки до окончания транзакции. На всём протяжении транзакции заблокированными могут оказаться даже некоторые строки, которые не соответствуют выборке в результате запроса. Такое блокирование гарантирует, что затронутые запросом строки не будут изменены или удалены в параллельном сеансе, пока текущая транзакция не будет завершена (независимо от того, будет ли она зафиксирована или произойдёт её откат). Эти блокировки не защищают от изменения или удаления те строки, которые еще не были охвачены просмотром, и не препятствуют вставке новых строк межу уже заблокированными строками."
7:25 а если первый done, а второй не done (подтвердилась только 1-я транзакция) ?
весьма!
а если в 2pc на этапе коммита мы должны уже финально снять сумму - но снятие суммы это обращение к стороннему сервису - например апи банка и все упало - то что в этом случаи?
думаю обращение к внешнему api должно происходить в последнюю очередь, т.е. придётся вернуться в CustomerMS ещё раз
тема раскрыта не полностью - что произойдет, если в 2PC одна транзакция в статусе Done, другая в статусе Failed? Как потом откатывать данные?
возможно также как в saga используются компенсаторные транзакции
А можно приболтать бизнес чтобы распределенных транзакций не было) Тот случай когда софт скилы эффективнее любого паттерна:) Но конечно не всегда такое возможно)
А как можно приболтать условный интернет-магазин или любой другой бизнес, где есть работа с деньгами?
обьясни детальнее что имеешь в виду. к какому решению нужно подвести бизнес? что на что поменять?
@@IvanFedulov Нужно найти тех людей от которых зависят твои тех решения. Например это может быть Продуктовнер, Аналитик, Системный аналитик, иногда разработчики (например из другой команды). Самое сложное здесь это придумать альтернативное бизнес решение которое будет 1) Без распределенных транзакций 2) Будет простым либо его сложность будет приемлемой. Вообще если подняться на уровень выше то это глобальная идея "Не создавать избыточной сложности" (Его еще называют KISS) и это конечно не только про распределенные транзакции. Будничный пример: Аналитик задизайнил ui. Но есть проблема данные с ui берутся из разных таблиц, и их DDL не оптимален - запрос сложный и медленный. Как делают мидлы? Они решают в лоб и пытаются выжить из sql все что можно - едят кактус. А делают синьеры ? Идут к аналитикам/продактам и предлагают свое решение. Скорее всего их это не устроит. Но тут важно донести почему "нет" и чем это "плохо". Зародить у них мысль о альтернативе. Бывают и позитивные примеры когда Аналитик говорит а так и правда лучше. И вы идете и пишете простой sql за 15 минут.
@@IvanFedulov Не совсем так. Тебе не нужно в прямом смысле подводить. По сути это переосмысление решения задачи, как техническое так и бизнесовое. Тебе нужно найти человека в команде от кого зависит твое техническое решение. Это может быть аналитик, разработчик (в том числе из другой команды), владелец продукта. Вы садитесь с этими людьми и придумываете фичу заново так чтобы она была проще и без распределенных транзакций. Приведу пример правда не про распределенные транзакции. У вас есть ui - данные для него берутся из двух таблиц. Структура таблиц такова что итоговый sql запрос получается а) Сложным для понимания б) медленным. Вы идете к владельцу продукта, и предлагаете разбить ui на два - на выходе получается два простых запроса. Вообщем это творческий путь. Волшебной таблетки здесь нет. В этом и состоит работа Senior разработчика на проекте - работать со сложностью - уменьшать ее.
Спасибо за доклад.
Разве для 2PC нельзя применить вариант снятия 20 рублей с баланса пользователя на стадии prepare? Чтобы не делать блокировку баланса для других транзакций
Нельзя. Вот представь, ситуацию, когда 20 р должны не сниматься а поступить на р/счет. Изначально на р/счету 0 р. Если первая трансакция еще не завершена, а вторая уже снимает эти 20 р за покупку какого-то товара и заканчивается успешно. Потом в первой происходит откат , а денег на р/счету уже нет
@@krasser650да в 2pc (которая по факту есть - пессимистический режим блокировок) так и нельзя. А вот в SAGA (которая по факту есть - оптимистический режим блокировок) - можно, т.к. там между первым событием и событием компенсации - баланс не заблокирован - и паралельные транзакции легко могут загнать в минус баланс. Для того и существуют 2 разных механизма, чтобы можно было выбрать - медленно, но надежно, или быстро - но с артефактами неконсистентности
В 2pc все равно же не атомарно потому что не факт что сможем отправить аборт. Чёт не понял
12:30 - программисты пишут код в базе данных... Как это? Какой механизм позволяет использовать этот код, он же в бд?
Привет. Например PL/SQL (Procedural Language / Structured Query Language)
У нас чуть ли не вся система на PLSQL написана. Позволяет добиваться высокой скорости при обеспечении полноценного ACID. Для финансовых систем это важно.
При этом это всё равно получается дикий монолит с характерными проблемами.
Вот как раз и рассматриваю варианты переноса части логики в микросервисы, но самой большой проблемой сейчас является решение вопроса согласованного чтения.
Кроме того, для разных операций нужно обеспечивать быстродействие разного характера: в одном случае быстродействие потоковой обработки событий, в другом: быстродействие одной длинной распределённой, но чувствительной транзакции.
Спасибо
музыка громковата
Микросервисы - модно, но порождает головную боль, монолит - классика..
Этот спор технологий разрешит прорыв в переходе к новым сетевым протоколам и новые технологии передачи данных по кабелю.. разумеется в пользу монолита
Не обманывайте людей. В патерне Saga нет транзакции. Не нужно делать подмену понятий типа сказав "локальная транзакция". Почитайте что такое транзакция. Честно было бы сказать что в Sega вы отказываетесь от транзакции и в случае не удачи, пытаетесь восстановить в обратном порядке данные, в случае не сложных систем вы будете иметь редко проблемы, а в сложных.....
В 2pc есть свои нюансы, но это транзакция, в Sega ее нет, и тот кто решит это использовать должен об этом знать.
Сама сага состоит из цепочки локальных для каждого микросервиса транзакций. Внутри одного сервиса это именно обычная транзакция. Но между-сервисами сага ведёт себя как начальник: сервис А успешно выполнил транзу? Ок кидаю событие "успех" тогда сервис Б может приступить к своей локальной транзакции. Если она неуспешна - сага создаст событие сервис-Б-ошибка по которому сага запустит откат транзакции на сервис-А.
В координаторе создаётся какая то транзакция)) откуда и как можно без бд сощдать транзакцию, что за фантазии.
транзакция - это логическая сущность. Набор операций которые должны быть выполненны или все сразу или ниодна. Можно из без всякой бд создать транзакционный самописный механизм. В БД они просто есть всегда и из коробки
есть транзакции в JMS. в спринге есть абстракция Transaction не привязанная к механизму.
Для 2pc: транзакционные вещи не должны выноситься в 2 микросервиса. Это не разный контекст, это один контекст. Всего должно было быть 3 микросервиса: тот, который про заказы знает, тот который про бабло знает и тот который считает заказы с баблом. Так вот запрос отправляется на 3 микросервис с транзакционной базой данных. Никаких распределённых транзакций. И когда всё ок, то два других микросервиса уменьшают кол-во продуктов у себя на основе данных их общего микросервиса с транзакциями, вычитают деньги. Т.е. по сути это 2 микросервиса на чтение и один на запись. И базы данных тут 2х видо: одна реляционная, и две nosql.
Если же у вас сделано так, как в видео, то вы на уровне проектирования неправильно определили границы контекста (частая проблема, при отсутствии опыта DDD). Не всегда контекст "заказов" это один сервис, контекст "счета" второй.
Так тут же нет контекста "счета" или это подобласть сервиса Order.
кошелек пользователя и заказы - такое разделение выглядит более чем правильно или я не понял ваш комментарий.
тогда вообще не нужны тут микросервисы, если их аж 3 уже надо.
@@ivani3237 обычно чтение данных происходит гораздо чаще, чем запись. Поэтому разумно вынести отдельно часть, которая записывает, чтобы ее не дергали с чтением. И две части, которые позволяют читать.
9:00 при подготовке понятно, а если при отправке команды commit один сервис упал и не закоммитил, как второй откатывать?
16:05 а что если мы упали на компенсационной транзакции и не смогли откатить?
После того, как все успешно сделали prepare и оркестратор (или как его там называют) начинает коммит на всех базах, пути назад нет. Если одна база не успела закоммитить и упала, то после рестарта та транзакция будет висеть, пока не дождется подтверждения коммита.
Компенсационные транзакции должны быть идемпотентными, то есть их можно выполнять сколько угодно результат не изменится
@@omgoood как такой возможно, если в данном случае компенсация это отмена созданного заказа?
@@IvanFedulov проверяем что заказ отменен - ок, не отменен - отменяем. Результат всегда один - заказ отменен, операция идемпотентна