Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Задачи

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Python: locking, optimistic, distributed, lock

Какие подходы используются для обеспечения корректной работы с балансами или другими критически важными конкурентными ресурсами?

Этот вопрос проверяет понимание методов синхронизации при работе с критичными ресурсами, такими как балансы, лимиты, инвентарь.

Короткий ответ

Для корректной работы с балансами применяют транзакции с блокировками строк (SELECT FOR UPDATE), оптимистическую блокировку с версионированием, распределённые блокировки (например, Redis Redlock), очереди событий, а также архитектурный принцип «один владелец ресурса». Выбор подхода зависит от нагрузки: для локальной БД подходит транзакционное обновление, а для распределённых систем используют очереди, шардирование и отдельный сервис-владелец балансов. Главная цель — сделать операции атомарными, последовательными и идемпотентными, чтобы избежать гонок и потерь данных.

Длинный ответ

1. Проблема конкурентных ресурсов

Определение.
Критически важный конкурентный ресурс — это данные, которые нельзя обновлять одновременно несколькими процессами без риска ошибки (например, баланс счёта, количество товара, лимиты).

Основные угрозы:

  • Гонки данных (race conditions).

  • Потеря обновлений.

  • Двойное списание.

  • Неконсистентные состояния.

2. Основные подходы к синхронизации

2.1. Транзакции + SELECT FOR UPDATE

Самый распространённый способ:

  1. Начинаем транзакцию.

  2. Делаем выборку строки с блокировкой:

SELECT * FROM accounts WHERE id = 123 FOR UPDATE;
  1. Проверяем баланс.

  2. Делаем UPDATE.

  3. Коммитим транзакцию.

Преимущества:

  • Простой, надёжный механизм.

  • Работает при средней нагрузке.

Недостатки:

  • Блокировки могут замедлять систему.

  • Возможны deadlock при неправильном порядке.

2.2. Оптимистическая блокировка (versioning)

Идея:

  • Каждая запись имеет поле version или updated_at.

  • Читаем запись → получаем version = X.

  • Пытаемся обновить:

UPDATE accounts 
SET balance = balance - 100, version = version + 1
WHERE id = 123 AND version = X;
  • Если обновлено 0 строк — конфликт → повторяем операцию.

Плюсы:

  • Нет тяжёлых блокировок.

  • Высокая производительность.

Минусы:

  • Нужно уметь повторять попытки безопасно.

2.3. Распределённые блокировки

Если ресурс разделён между несколькими сервисами:

  • Используют Redis Redlock, ZooKeeper locks, Consul locks.

  • Важны гарантии:

    • TTL блокировки.

    • Обновление lease.

    • Предотвращение split-brain.

Пример Redis:

Python

lock = redis.lock("balance:123", timeout=5)
with lock:
    update_balance()

2.4. Сервис-владелец ресурса (actor-like model)

Архитектурный подход:

  • Только один сервис отвечает за обновление ресурса.

  • Все остальные посылают ему запросы/команды.

  • Состояние изменяется строго последовательно.

Преимущества:

  • Невозможны гонки между сервисами.

  • Упрощает логику.

Недостатки:

  • Увеличивает нагрузку на сервис-владелец.

  • Нужна высокая доступность.

2.5. Очереди событий (event sourcing style)

  • Все изменения баланса превращаются в события (например, "debit 100").

  • События помещаются в очередь (Kafka/Rabbit).

  • Консьюмер обрабатывает их строго последовательно.

Плюсы:

  • Очень надёжно и масштабируемо.

  • Естественная история изменений.

Минусы:

  • Сложнее реализовать.

  • Требует сильной дисциплины.

2.6. Шардирование ресурса

Если много конкурирующих операций:

  1. Разделить ресурсы по шардам.

  2. Каждый шар обрабатывается отдельным воркером.

  3. Баланс/инвентарь обновляются только «назначенным» воркером.

Это уменьшает конкуренцию и распределяет нагрузку.

3. Дополнительные техники

3.1. Идемпотентность операций

  • Каждая операция должна иметь operation_id.

  • Выполнение операции проверяется по этому ID.

  • Повторы не меняют финальное состояние.

3.2. Ограничение повторных попыток

Часто важно:

  • Лимитировать количество обработок.

  • Логировать все попытки.

3.3. Атомарные операции UPDATE

Пример:

UPDATE accounts 
SET balance = balance - 100 
WHERE id = 123 AND balance >= 100;

Если обновлено 1 строка — успех.
Если 0 — недостаточно средств.

4. Вывод

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

  • Аватар

    Python Guru

    Sergey Filichkin

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.

Уровень

  • Рейтинг:

    4

  • Сложность:

    7

Навыки

  • Python

    Python

Ключевые слова

#locking

#optimistic

#distributed

#lock

Подпишись на Python Developer в телеграм

  • Аватар

    Python Guru

    Sergey Filichkin

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.