Transaction boundaries и atomicity¶
Раздел 04 · Типы достоверности
Тип материала: инженерный разбор. Схемы и примеры иллюстративные. Рекомендации — INFERENCE; учебные параметры — HYPOTHETICAL.
Проверка источников: 2026-11-02. Версии и границы первоисточников перечислены в конце. Documented contracts не означают выполненный runtime test.
Принцип работы и границы¶
Атомарность относится к изменениям внутри конкретной транзакции и конкретного resource manager. В PostgreSQL проводки, operation record и outbox могут принадлежать одной transaction. INSERT в БД и Kafka produce находятся в разных commit domains, даже если выполняются одной функцией приложения.
FACT: acknowledged PostgreSQL commit и durability зависят от WAL и выбранной конфигурации; asynchronous commit допускает потерю недавно подтверждённых транзакций при crash. PostgreSQL 17. INFERENCE: для денежных операций явно определите локальную durability и допустимую потерю при failover, а не ограничивайтесь словом ACID.
Outbox делает бизнес-запись и намерение публикации атомарными. Relay всё равно может опубликовать дважды. Inbox на downstream нужен отдельно. Transaction commit может завершиться на сервере до обрыва ответа: клиент видит UNKNOWN outcome, а не доказанный rollback.
Иллюстративная архитектура¶
flowchart LR
A[Command with stable ID] --> TX[PostgreSQL transaction]
TX --> L[Ledger postings]
TX --> O[Outbox row]
O --> R[Relay]
R --> K[Kafka]
K --> I[Downstream inbox]
Failure scenarios¶
Отдельный outbox INSERT после business commit теряется при crash. Удаление outbox до broker acceptance теряет событие. Broker accept до relay marker даёт повтор. Принудительный failover на отставший standby может потерять и ledger record, и его operation marker.
Recovery protocol¶
- При lost ACK проверить operation_id и повторить ту же команду через constraints.
- Восстановить durable outbox backlog; отправлять без смены event_id.
- Не отмечать delivered до подтверждения broker; failed marker допускает повтор.
- После failover определить потерянный WAL interval и сверить опубликованные события с ledger. Если событие ушло, а source transaction потеряна, требуется расследование и компенсация, не слепое восстановление баланса из Kafka.
Trade-offs и критерии выбора¶
Большая транзакция дольше держит locks и WAL, маленькие транзакции усложняют общий инвариант. Saga даёт промежуточные состояния и компенсации, а не один ACID commit нескольких сервисов. 2PC требует поддержки участников и recovery prepared transactions.
FinTech и iGaming¶
Выплата: debit, credit, immutable postings и outbox фиксируются вместе в пределах одного authoritative ledger. Email receipt и аналитика восстанавливаются отдельно. Межбанковское перечисление требует состояния pending до внешней финальности.
Практический пример¶
Читайте исходный ledger walkthrough и сценарий B. В lab Outbox проверяются два раздельных crash windows. SQL runtime без PostgreSQL остаётся NOT_RUN.
Типичные ошибки проектирования¶
Держать DB transaction открытой во время remote HTTP; считать rollback приложения откатом уже committed запроса; посылать новую команду после lost ACK.
Вопросы на собеседовании¶
Почему outbox не exactly-once delivery? Relay marker и broker acceptance не один commit; duplicate компенсируется stable identity и inbox.
Увидел timeout на COMMIT — можно отменить операцию? Нельзя делать такой вывод: исход неизвестен, требуется разрешение по operation ID.
Дополнительные источники¶
- PostgreSQL asynchronous commit — 17.
- PostgreSQL isolation — 17.
- Kafka 4.1 design — 4.1.