Проверяет понимание распределённых транзакций, их необходимости и проблем согласованности данных в микросервисной архитектуре.
Распределённая транзакция — это набор операций, выполняемых над данными в разных системах (базах данных, сервисах), которые должны быть выполнены атомарно: либо все успешно, либо ни одна. В монолитных приложениях транзакции управляются одной базой данных, но в микросервисной архитектуре данные часто распределены, и требуется координация.
Основная проблема — обеспечение ACID (атомарность, согласованность, изоляция, долговечность) в распределённой среде. Два популярных подхода:
class Saga {
constructor() {
this.steps = [];
}
addStep(execute, compensate) {
this.steps.push({ execute, compensate });
}
async run() {
const executed = [];
for (const step of this.steps) {
try {
await step.execute();
executed.push(step);
} catch (err) {
for (const s of executed.reverse()) {
await s.compensate();
}
throw err;
}
}
}
}
// Использование:
const saga = new Saga();
saga.addStep(
() => db1.update({ id: 1, amount: -100 }),
() => db1.update({ id: 1, amount: 100 })
);
saga.addStep(
() => db2.update({ id: 2, amount: 100 }),
() => db2.update({ id: 2, amount: -100 })
);
saga.run();Распределённые транзакции необходимы в системах с несколькими источниками данных. Для высоконагруженных микросервисов чаще используют Saga из-за его асинхронности и отсутствия блокировок, хотя 2PC подходит для строгих требований к согласованности.