Что такое протокол двухфазного коммита (2PC) в распределённых системах?

Ответ

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

Фазы протокола:

  1. Фаза подготовки (Prepare)

    • Координатор отправляет всем участникам команду prepare.
    • Каждый участник выполняет локальные операции транзакции, блокирует ресурсы и записывает данные в лог, но не фиксирует.
    • Участник голосует: отправляет координатору YES (готов) или NO (не готов / ошибка).
  2. Фаза фиксации (Commit/Rollback)

    • Если все участники ответили YES: координатор отправляет команду commit. Участники фиксируют изменения и освобождают ресурсы.
    • Если хотя бы один участник ответил NO: координатор отправляет команду rollback. Все участники откатывают изменения.

Пример псевдокода:

// Координатор
boolean allPrepared = participants.stream()
                                  .allMatch(p -> p.prepare(transactionData));
if (allPrepared) {
    participants.forEach(p -> p.commit(transactionId));
} else {
    participants.forEach(p -> p.rollback(transactionId));
}

Ключевые проблемы 2PC:

  • Блокировки ресурсов: Участники блокируют данные на время всего протокола, что снижает производительность.
  • Отказ координатора: Если координатор выходит из строя после фазы подготовки, участники остаются в заблокированном состоянии (проблема подвешенной транзакции).
  • Синхронное ожидание: Протокол является синхронным и блокирующим.

Альтернативы: Для повышения доступности и производительности используют протоколы вроде трёхфазного коммита (3PC) или паттерн Saga (компенсирующие транзакции).

Ответ 18+ 🔞

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

Первая фаза — подготовка (Prepare). Ты, как координатор, орешь на всех холопов: «Эй, мудаки, готовьтесь! Сейчас будем делать операцию «Переворот»!». Каждый холоп бежит, делает всю черновую работу у себя в конуре: данные меняет, ресурсы блокирует, всё в лог записывает, но НЕ ФИКСИРУЕТ. То есть палец уже на курке, но не жмёт. Потом каждый тебе докладывает: «Да, босс, готов» (YES) или «Нет, босс, у меня тут ошибка, не могу» (NO).

Вторая фаза — фиксация или откат (Commit/Rollback). Ты смотришь на ответы. Если ВСЕ, блядь, сказали «готов» — ты командуешь: «ВПЕРЁД, СУКИ, КОММИТ!». И все холопы разом нажимают на свои курки, фиксируют изменения. А если хоть один пидор сказал «не готов» — ты орешь: «ВСЕМ ОТМЕНИТЬ, ОТКАТ! НАХУЙ!». И все холопы, матерясь, откатывают всё назад, как будто ничего и не было.

Вот тебе пример кода, чтоб ты понимал, как это выглядит в голове у координатора:

// Координатор
boolean allPrepared = participants.stream()
                                  .allMatch(p -> p.prepare(transactionData));
if (allPrepared) {
    participants.forEach(p -> p.commit(transactionId));
} else {
    participants.forEach(p -> p.rollback(transactionId));
}

Всё вроде красиво, да? Но тут, как всегда, есть подводные ебучки, которые всё портят.

Главные проблемы, из-за которых все его ненавидят:

  1. Блокировки на овердохуища. Пока этот цирк с конями идёт, все холопы держат ресурсы заблокированными. Другие транзакции стоят и ждут, как лохи. Производительность летит в пизду.
  2. Координатор — единая точка отказа. Это самая пиздатая проблема. Представь: ты (координатор) отдал команду «готовьтесь», все ответили «да», и в этот момент у тебя, блядь, сердце остановилось. Ты сдох. А холопы-то сидят и ждут твоей команды «коммит» или «откат». И ждут они её до скончания века, в заблокированном состоянии. Это называется «подвешенная транзакция», и это пиздец.
  3. Всё синхронно и медленно. Пока все не ответят, дальше ни шагу. Один тормоз — и все стоят.

Из-за этого всего умные дяди придумали альтернативы. Например, трёхфазный коммит (3PC), который пытается решить проблему с дохлым координатором, добавляя ещё одну фазу — «пред-коммит». Или Saga — там транзакция выполняется по шагам, и если на каком-то этапе пиздец, то запускаются компенсирующие транзакции, которые откатывают каждый предыдущий шаг. Это как сделать ремонт, а потом, если денег нет, продавать по одному кирпичу обратно.