Назад к вопросам
Senior
3
Есть микросервис для списания средств с баланса пользователя. При репликации сервиса возникает проблема race condition. Как решить эту проблему?
Компании, где спрашивали
ООО Дэстэн Партнерс
Ответ от нейросети
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("не удалось списать средства из-за конфликта")
}