Sobes.tech
Back to questions
Senior
5

Как гарантировать консистентность данных — что сообщение и сохранится в БД, и будет доставлено получателю?

Companies where asked
Ozon ФинтехOzon Финтех

Answer from AI

sobes.tech AI

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

Основные подходы:

  1. Transactional Outbox — в рамках одной транзакции сохраняется и основная бизнес-данные, и сообщение в специальной таблице outbox. Затем отдельный процесс читает и отправляет сообщения.

  2. Two-Phase Commit (2PC) — распределённая транзакция между базой и брокером сообщений, но часто сложна и снижает производительность.

  3. Idempotent Consumers и повторная отправка — если невозможно атомарно, то делают отправку сообщений с возможностью повторной обработки без побочных эффектов.

В Go можно реализовать transactional outbox примерно так:

func SaveDataAndOutbox(db *sql.DB, data Data, message Message) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // Сохраняем данные
    _, err = tx.Exec("INSERT INTO data_table (...) VALUES (...)", ...)
    if err != nil {
        return err
    }

    // Сохраняем сообщение в outbox
    _, err = tx.Exec("INSERT INTO outbox (event_type, payload) VALUES (?, ?)", message.Type, message.Payload)
    if err != nil {
        return err
    }

    return tx.Commit()
}

Таким образом, либо и данные, и сообщение сохранятся, либо не сохранятся вовсе.