Перейти к содержанию

B. PostgreSQL commit с потерянным ACK

Раздел 04 · Failure matrix

Тип материала: учебный архитектурный сценарий. Не описывает систему конкретной компании. Все операции, IDs и числа ниже — HYPOTHETICAL.

Проверка источников: 2026-11-02. Интеграционный fault test этого сценария — NOT_RUN; documented behavior и предлагаемый recovery не считаются выполненным испытанием.

Normal flow

Клиент отправляет операцию с устойчивым operation_id, а PG 17 атомарно сохраняет request hash, проводки и ответ. Суммы — minor units. Для локальной durability предполагаются корректные fsync/WAL и synchronous_commit; failover durability задаётся отдельно. Успех сервера и получение success клиентом — разные события.

Иллюстративная схема нормального пути:

flowchart LR
 C[Stable command ID] --> D[Authoritative transaction]
 D --> P[Postings and saved response]
 P --> A[Client receives ACK]

Failure timeline

sequenceDiagram
 participant C as Client
 participant D as PostgreSQL
 C->>D: Command op1
 D->>D: Durable COMMIT op1
 D--xC: ACK lost
 Note over C: Timeout means UNKNOWN
 C->>D: Retry same op1 and hash
 D-->>C: Original committed response

Состояние систем после отказа

Участник Durable состояние Неопределённость / проверка
PostgreSQL Может быть committed op1 Обрыв возможен и до commit: нужен lookup/guard
Client Не получил ответ Нельзя считать failed или создавать op2
External systems Могли увидеть outbox event Сверить по op1 после failover

Retry и replay

Новый request использует тот же ID и payload. Если первая transaction ещё исполняется, retry может ждать unique key/row lock; отсутствие строки в раннем SELECT не разрешает обойти constraint. Читать только async replica опасно: она может ещё не видеть committed op1.

Обнаружение проблемы

Рост ambiguous responses, client retries и unique conflicts, долгие sessions/locks, несовпадение client status и authoritative operation table. После promotion нужен анализ WAL gap: stale standby может потерять подтверждённую запись.

Recovery protocol

  1. Назначить operation статус unresolved, сохранить request evidence.
  2. Читать authoritative DB и повторять ту же guarded команду, ограничивая deadline.
  3. Вернуть сохранённый ответ, если identity/hash совпадают; конфликт изолировать.
  4. Если failover изменил durable history, сверить provider/ledger/outbox evidence до нового эффекта.
  5. Не проводить компенсацию только потому, что клиент получил timeout.

Гарантии и trade-offs

Unique operation record и effect в одной transaction обеспечивают единственный результат при сохранной DB history. ACK uncertainty устраняется lookup/retry protocol, а не transport retries сами по себе. Не проверены реальные сетевые drops, PG failover и synchronous replication. Дополнительные lookups и unresolved workflow увеличивают latency.

Практическая проверка

PG concurrency lab задаёт independent sessions. Для lost ACK требуется test proxy/failpoint, который обрывает именно ответ после durable evidence; произвольный kill client не доказывает, где был commit.

Источники и версии