← Назад ко всем вопросам

Что такое distributed transactions и почему они проблемны

1️⃣ Как кратко ответить

Distributed transactions — это транзакции, которые охватывают несколько независимых систем или баз данных. Они проблемны из-за сложности координации между системами, риска частичных отказов и необходимости обеспечения согласованности данных, что может привести к снижению производительности и увеличению задержек.

2️⃣ Подробное объяснение темы

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

Зачем нужны распределенные транзакции

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

Как работают распределенные транзакции

Распределенные транзакции обычно реализуются с использованием протокола двухфазной фиксации (2PC — Two-Phase Commit). Этот протокол состоит из двух фаз:

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

    • Координатор транзакции отправляет запрос на подготовку (prepare request) всем участвующим системам.
    • Каждая система выполняет локальные проверки и резервирует ресурсы, необходимые для выполнения транзакции.
    • Если система готова зафиксировать изменения, она отвечает "готово" (ready); в противном случае — "отказ" (abort).
  2. Фаза фиксации (Commit Phase):

    • Если все участники ответили "готово", координатор отправляет команду на фиксацию (commit) всем системам.
    • Если хотя бы один участник ответил "отказ", координатор отправляет команду на откат (rollback).

Проблемы распределенных транзакций

  1. Сложность координации:

    • Координация между несколькими системами требует сложной логики и надежного сетевого взаимодействия. Любая задержка или сбой в сети может привести к проблемам с согласованностью.
  2. Частичные отказы:

    • В распределенной системе одна из систем может выйти из строя, что приведет к необходимости отката транзакции. Это может быть сложно и затратно по времени.
  3. Производительность:

    • Протокол 2PC требует нескольких раундов коммуникации между системами, что увеличивает задержки и снижает общую производительность системы.
  4. Согласованность данных:

    • Обеспечение согласованности данных в распределенной системе — сложная задача. Необходимо учитывать различные сценарии отказов и обеспечивать, чтобы данные оставались согласованными даже в случае сбоев.

Пример кода

Рассмотрим упрощенный пример использования распределенной транзакции с использованием Java и JTA (Java Transaction API):

import javax.transaction.UserTransaction;
import javax.naming.InitialContext;
​
public class DistributedTransactionExample {
​
    public static void main(String[] args) {
        try {
            // Получаем объект UserTransaction из JNDI
            UserTransaction utx = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
​
            // Начинаем транзакцию
            utx.begin();
​
            // Выполняем операции в первой базе данных
            performDatabaseOperation1();
​
            // Выполняем операции во второй базе данных
            performDatabaseOperation2();
​
            // Если все операции успешны, фиксируем транзакцию
            utx.commit();
        } catch (Exception e) {
            try {
                // В случае ошибки откатываем транзакцию
                utx.rollback();
            } catch (Exception rollbackEx) {
                rollbackEx.printStackTrace();
            }
            e.printStackTrace();
        }
    }
​
    private static void performDatabaseOperation1() {
        // Логика для выполнения операции в первой базе данных
    }
​
    private static void performDatabaseOperation2() {
        // Логика для выполнения операции во второй базе данных
    }
}
  • Получение UserTransaction: Используется для управления транзакцией. Получаем его через JNDI.
  • Начало транзакции: utx.begin() начинает новую транзакцию.
  • Выполнение операций: performDatabaseOperation1() и performDatabaseOperation2() представляют операции в разных базах данных.
  • Фиксация транзакции: utx.commit() фиксирует изменения, если все операции успешны.
  • Откат транзакции: В случае ошибки вызывается utx.rollback(), чтобы отменить все изменения.

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

Тема: Микросервисы
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки