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

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

В 1991 году (30 лет назад!) был принят стандарт X/Open XA, который описывает распределенные транзакции. Этот стандарт поддерживают практически все БД, и многие middleware, такие как Tuxedo, MQSeries, WebLogic, WebSphere, JBoss и прочие. Однако когда берешь что-то новомодное, ощущение, что люди вообще не в курсе того, что делали до них. Сам недавно столкнулся с ситуацией, когда надо было сделать распределенную транзакцию с участием PostgreSQL и RabbitMQ, и оказалось, что у Rabbit'а нет ничего похожего на XA, пришлось что-то самому костылить.

Далее не в адрес автора поста, а просто немного нытья о представителя поколения X. У меня иногда ощущение, что где-то после 2000-го в нашу индустрию пришли какие-то хипстеры, которые считают, что эти скучные бумеры и поколение X в принципе не могли ничего путного придумать (их ведь Цукерберг научил, что молодые просто умнее), и начали по-новой придумывать то, что уже давно придумано и хорошо работает. И не всегда у них получается лучше. Ньютон видел дальше, потому что стоял на плечах гигантов, а не изобретал всю физику и математику с нуля. Будь умный, будь как Ньютон.

Хотел уточнить в статье, но забыл — речь идет не про распределенные транзакции в рамках БД, а именно про распределенный процесс, который стремится к ACID.


Про стандарт выше тоже знаю, но на практике покрыть распределенный процесс одной "распределенной транзакцией БД" не выйдет — просто пропускная способность системы снизится почти до нуля, т.к. время одной такой транзакции будет до десятков минут, а по пути будет куча блокировок.


Кроме того, XA не решит проблемы конвейерных процессов: когда вам нужно для создания сущности пройтись по шагам, на каждом из который делается дюжина вызовов к какому-нибудь вендорскому решению (привет, vmware), но при этом уметь обработать ошибки, не переделывая всю цепочку целиком, а еще уметь переживать падение приложения без прерывания транзакции.


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

По поводу тезиса


после 2000-го в нашу индустрию пришли какие-то хипстеры… и начали по-новой придумывать то, что уже давно придумано и хорошо работает

Вы заблуждаетесь, если считаете, что было придумано что-то новое. Документоориентированные БД и брокеры сообщений существовали еще до X/Open XA. Разница в том, что изолированная транзакция (вроде сериализации через MVCC) — штука довольно дорогая сама по себе, а распределенная транзакция так и вовсе. Многим процессам важны скорость в ущерб атомарности или консистентности. Брокеры же сообщений вообще не про транзакции (хотя Kafka, являющаяся по сути БД, умеет в транзакции при записи).


Новые инструменты сделаны не потому, что "хипстеры хотели придумать что-то новое" — PostgreSQL до сих пор остается одной из самых популярных БД, хотя сложно представить что-то менее хипстерское. "Новые" инструменты решают в основном проблемы масштаба или скорости — когда либо данные перестает быть возможно держать на обычных БД вроде постгреса, либо скорость чтения/записи превышает возможности "старых" решений.


В случае с документоориентированными БД, за высокую скорость записи приходится дорого платить — контроль за консистентностью данных переходит с БД на приложение и плечи разработчика.


Аналогично с распределенными гетерогенными приложениями — за возможность делать масштабируемые сервисы, и разрабатывать language-agnostic и db-agnostic компоненты приходится платить тем, что контроль ACID переезжает из БД в приложение и также ложится на плечи разработчика/артихектора.


Одно можно сказать точно — покуда можно избежать "распределенных" сущностей, их нужно избегать.

Документоориентированные БД и брокеры сообщений существовали еще до X/Open XA
И что? Без общего стандарта каждый делал что-то свое. С появлением единого стандарта стало намного проще разрабатывать (единый API) и по ходу дела менять компоненты систем, Oracle на PostgreSQL, WebLogic на JBoss и т.п. Не вижу, как это опровергает то, что я написал.

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

Новые инструменты сделаны не потому, что «хипстеры хотели придумать что-то новое» — PostgreSQL до сих пор остается одной из самых популярных БД, хотя сложно представить что-то менее хипстерское.
А разве я где-то написал, что PostgreSQL — хипстерский? В моем комментарии достаточно ясно сказано, что претензии у меня были к Rabbit'у.

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

Кроме того, XA не решит проблемы конвейерных процессов: когда вам нужно для создания сущности пройтись по шагам, на каждом из который делается дюжина вызовов к какому-нибудь вендорскому решению (привет, vmware), но при этом уметь обработать ошибки, не переделывая всю цепочку целиком, а еще уметь переживать падение приложения без прерывания транзакции.
А вот это как раз XA хорошо умеет, при условии, что для каждого компонента, участвующего в транзакции (который умеет как коммитить, так и откатывать) есть XA resource manager. Когда даешь transaction manager'у commit или rollback, он дергает все причастные resource manager'ы, чтобы они сделали свое дело.

Вы пробудили во мне интерес, поиграюсь на досуге, спасибо. Интересно, что там с отказоустойчивостью — когда инстанс БД приляжет, или там приложение, через которое бежит транзакция, перестанет отвечать, и входящие в транзакцию сообщения подхватит другая реплика.

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


Окей, мы сказали про распределённый конечный автомат. Давайте же дальше держать планку.


Rainer Prinoth — Construction of Distributed Systems from Cycle-Free Finite Automata
Roberto Gorrieri — Verification of finite-state machines: A distributed approach (Journal of Logical and Algebraic Methods in Programming Volume 96, April 2018, Pages 65-80)


… но вместо обобщения, нам рассказывают про "паттерн, в отношении которого нет консенсуса". Ух.

Спасибо за ссылки!


В каком виде ожидали обобщение?

Например, "и я попробовал описать свой конечный автомат, используя <умный софт> и оказалось, что было два edge-case'а про которые я не думал, я сделал так, что <умный софт> больше не ругается, и теперь у меня есть доказательство сохранения инвариантов; а сейчас я нашёл метод экспортировать оптимальную схему из <умный софт> в свой софт."

Хмм, попробую такое сформулировать и добавить. Конец действительно немного повис в воздухе, спасибо за идею.

Вот здесь обсуждение похожей проблемы, только не вникая в детали реализации.
Вместе эти статьи создают более полную картину по распределенным межсервисным транзакциям, а точнее по решаемым проблемам.
Уважаемый MaximTsepkov создал цикл интереснейших статей по распределённым системам, и в последней статье расписал 3 варианта: Синхронный, Асинхронный и Реактивный (Асинхронный+callback).
Если я правильно понял, распределенные межсервисные транзакции пока не имеют красивого (надежного) архитектурного решения и авторы делятся подходами и реализациями.

Как мне кажется, чтоб описывать реализации, нужно сначала расписать все возможные use cases и определить требования.
Обработав use cases придем к чему-то, типа:
1. Виды дочерних вызовов: последовательный, параллельный
2. Типы вызова: синхронный, асинхронный
3. Ошибки и реакции на них:
— Фатальная: откат всей транзакции без повторных попыток.
Например нарушение бизнес логики
— Сбой. Например сетевой (не пришло подтверждение)
… ???

Решения для требований, особенно №3, как мне кажется, и определят надежную архитектуру.

Очень интересно, спасибо.


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


Обработка ошибок — это больное место в длинных конвейерных процессах) В простом случае в случае технической/инфраструктурной ошибки делаются ретраи, и при логической ошибке цепочка откатывается по шагам обратно с выполнением компенсирующих действий. Но на деле все не так просто...

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории