Sobes.tech
Back to questions
Senior
4

Есть микросервис для списания средств с баланса пользователя. При репликации сервиса возникает проблема race condition. Как решить эту проблему?

Companies where asked
ООО Дэстэн Партнерс

Answer from AI

sobes.tech AI

Проблема race condition при списании средств в микросервисе с репликацией возникает из-за одновременного доступа нескольких экземпляров к одним и тем же данным. Чтобы решить её, можно использовать следующие подходы:

  • Оптимистичная блокировка (Optimistic Locking): хранить версию записи или timestamp, при обновлении проверять, что версия не изменилась. Если изменилась — повторять операцию.
  • Транзакции и блокировки на уровне базы данных: использовать транзакции с блокировкой строк (например, SELECT ... FOR UPDATE), чтобы гарантировать последовательный доступ.
  • Использование распределённых блокировок: например, через Redis с Redlock или Zookeeper, чтобы только один сервис мог списывать средства в момент времени.
  • Идемпотентные операции и очереди: обрабатывать списания через очередь сообщений, чтобы гарантировать последовательность и избежать параллельных изменений.

Пример с оптимистичной блокировкой в Go (псевдокод):

func DeductBalance(userID string, amount float64) error {
    for i := 0; i < maxRetries; i++ {
        user, err := db.GetUser(userID)
        if err != nil {
            return err
        }
        if user.Balance < amount {
            return errors.New("недостаточно средств")
        }
        newBalance := user.Balance - amount
        // Обновляем с проверкой версии
        updated, err := db.UpdateBalanceIfVersionMatches(userID, newBalance, user.Version)
        if err != nil {
            return err
        }
        if updated {
            return nil // успешно
        }
        // Иначе версия изменилась, повторяем
    }
    return errors.New("не удалось списать средства из-за конфликта")
}