System Design
Distributed Transactions
Проблема распределённых транзакций
**Почему это сложно?** В монолите: одна БД = одна транзакция с ACID. В микросервисах: каждый сервис имеет свою БД. Как обеспечить атомарность операции, затрагивающей несколько сервисов?
**Проблемы сети (Fallacies of Distributed Computing)** 1. **Network is NOT reliable** - сообщения теряются 2. **Latency is NOT zero** - timeout ≠ failure 3. **Bandwidth is NOT infinite** - retry storms 4. **Network is NOT secure** - man-in-the-middle
**Подходы к решению:** | Подход | Consistency | Availability
| **2PC** | Strong | Low | Medium | | **Saga** | Eventual | High | High | | **Outbox** | Eventual | High | Medium | | **TCC** | Strong | Medium | High |
Что вы узнали о Проблема распределённых транзакций?
Two-Phase Commit (2PC)
**2PC - классический протокол распределённых транзакций** Участники: - **Coordinator** - управляет транзакцией - **Participants** - выполняют операции Фазы: 1. **Prepare (Vote)** - все готовы? 2. **Commit/Abort** - финальное решение
**Blocking Problem - главный недостаток 2PC** Что если Coordinator упал после PREPARE, но до COMMIT? → Participants держат locks → Ждут решения от Coordinator → **BLOCKED** - ни commit, ни abort → Другие транзакции не могут работать с locked данными
**Когда использовать 2PC:** ✅ Подходит: - Базы данных с XA transactions - Короткие транзакции (секунды) - Небольшое число участников (2-3) - Надёжная локальная сеть ❌ НЕ подходит: - Микросервисы через интернет - Долгие бизнес-процессы (минуты/часы) - Много участников (>5) - Нужна высокая доступность
Что вы узнали о Two-Phase Commit (2PC)?
Saga Pattern
**Saga - альтернатива 2PC для микросервисов** Вместо distributed lock: - Последовательность локальных транзакций - Каждый шаг имеет **компенсирующую транзакцию** - При ошибке - откат через компенсации Преимущество: нет блокировок, высокая доступность
**Два стиля координации Saga:** 1. **Choreography** - децентрализованный - Сервисы общаются через события - Каждый знает, что делать при получении события - Нет единой точки управления 2. **Orchestration** - централизованный - Orchestrator управляет всеми шагами - Знает полный workflow - Единая точка контроля
**Semantic Lock - защита от "грязных" чтений в Saga** Проблема: между T1 и T2 другой процесс может прочитать промежуточное состояние. Решение: добавить флаг `pending` к записям: - T1: создать Order со статусом `PENDING` - T3 success: обновить на `COMPLETED` - Compensation: обновить на `CANCELLED` Другие процессы проверяют статус перед использованием.
Что вы узнали о Saga Pattern?
Transactional Outbox Pattern
**Проблема: Dual Write** Как атомарно: 1. Сохранить данные в БД 2. Отправить событие в Message Broker Если БД commit, но message failed → inconsistency Если message sent, но БД rollback → inconsistency
**Outbox Table Schema:**
**Важно:** Partial index для быстрого поиска необработанных событий.
**At-Least-Once Delivery** Outbox гарантирует at-least-once (не exactly-once): - Message Relay может отправить событие - Но упасть до UPDATE processed_at - При рестарте отправит повторно → Consumers ДОЛЖНЫ быть **idempotent**!
Что вы узнали о Transactional Outbox Pattern?
Idempotency
**Idempotency - ключ к надёжным distributed systems** Операция idempotent, если: - Выполнение N раз даёт тот же результат, что и 1 раз - f(f(x)) = f(x) Примеры: - ✅ SET balance = 100 (idempotent) - ❌ SET balance = balance + 100 (NOT idempotent) - ✅ DELETE WHERE id = 5 (idempotent) - ❌ INSERT INTO table (NOT idempotent - duplicate)
**Реализация Idempotency Key:**
**Паттерны Idempotent Operations:** | Operation | Idempotent?
| `UPDATE SET x = 5` | ✅ Yes | - | | `UPDATE SET x = x + 1` | ❌ No | Store final value | | `INSERT` | ❌ No | UPSERT / ON CONFLICT | | `DELETE WHERE id = X` | ✅ Yes | - | | `Send notification` | ❌ No | Dedup by event_id |
Что вы узнали о Idempotency?