Механизмы управления конкурентным доступом к данным в RDBMS


Что содержится в статье ⌄
  • Механизмы управления конкурентным доступом в rdbms
  • Mvcc в postgresql
  • Уровни изоляции транзакций в базах данных
  • Select for update блокировка записей
  • Advisory locks
  • Предикативные блокировки
  • Vacuum процесс

1. MVCC – Multi-Version Concurrency Control

Это дефолтный механизм в различных RDBMS, включая Postgres. При выполнении UPDATE/DELETE операций вместо overwrite создается новая версия записи. Старые данные помечаются как “DEAD”, и будут удалены операцией VACUUM.

VACUMM может быть вызван как вручную, так и автоматически (AUTOVACUUM). Удаление “DEAD” данных происходит когда все активные транзакции перестают видеть старые версии.

MVCC разруливает проблемы многопоточного доступа на базовом уровне:

  • Запись не блокируется читателями; вместо этого создается новая версия данных
  • В момент операции записи, читатели видят снапшот предыдущих данных.

При этом это происходит без блокировок для чтения, но изменения могут блокировать друг друга. В таком случае поведение будет зависеть уже от уровня изоляции транзакций.


2. Transactions

Некоторые задачи координации доступа к данным можно эффективно решить с помощью транзакций и настройки уровня изоляции тразнаций:

  • Read Committed
  • Repeatable Read
  • Serializable

3. select for update

Конструкция “select for update” – взятие лока на конкретные записи уровне БД. Лок будет взят сразу после выполнения этой конструкции, а отпущен в момент COMMIT и ROLLBACK транзации.

Особенность конструкции в том, что это не предикативная блокировка, т.е. невозможно заблокировать запись, которой еще нет.


4. Advisory locks

Наиболее гибкий вариант – клиент БД должен сам взять лок по конкретному числу int. Идентификатор может быть любым числом, не обязательно существующим id записи, хотя это один из вариантов.

Выглядит это так:

SELECT pg_advisory_xact_lock(42);  -- Блокировка на время текущей транзакции

Также есть вариант взять лок на время сессии.

Другими словами – мы взяли лок с id=42. Если другой поток попытается взять лок с id=43 – это произойдет сразу, но если с id=42 – то потребуется, чтобы изначальная транзакция завершилась.