Как понять эту многосекционную обработку запроса без примера атомарной фиксации?

#apache-kafka #architecture #atomic #partition #system-design

Вопрос:

Я читаю Designing Data-Intensive Applications by Martin Kleppmann

В Aiming for Correctness(Page 523) нем он привел пример Multi-partition request processing :

мы хотим вычесть деньги со счета A и добавить эти деньги на счет B как атомарную транзакцию, что означает либо полный успех, либо полный провал

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

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

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

  1. Запрос на перевод денег со счета A на счет B получает уникальный идентификатор запроса от клиента и добавляется в раздел журнала на основе идентификатора запроса.
  1. Потоковый процессор считывает журнал запросов. Для каждого сообщения запроса он отправляет два сообщения в выходные потоки: инструкцию по дебету на счет плательщика A (разделенную на A) и инструкцию по кредиту на счет получателя платежа B (разделенную на B). Исходный идентификатор запроса включается в эти отправленные сообщения.
  1. Дальнейшие обработчики используют потоки кредитных и дебетовых инструкций, дедуплицируют их по идентификатору запроса и применяют изменения к остаткам на счетах.

Шаги 1 и 2 необходимы, потому что, если клиент напрямую отправит инструкции по кредиту и дебету, потребуется атомарная фиксация между этими двумя разделами, чтобы гарантировать, что произойдет либо то, либо другое, либо ни то, ни другое. Чтобы избежать необходимости в распределенной транзакции, мы сначала надежно регистрируем запрос в виде одного сообщения, а затем получаем инструкции по зачислению и списанию средств из этого первого сообщения. Записи с одним объектом являются атомарными почти во всех системах обработки данных, поэтому запрос либо появляется в журнале, либо нет, без какой-либо необходимости в многосекционной атомной фиксации.

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

Если в step3 , "apply the changes to the account balances" , вычет из учетной записи A завершается неудачей, но добавление в учетную запись B завершается успешно, это все еще не атомарно? Как это решает проблему?