Открыть сервис

Многоверсионное управление

Многоверсионное управление (англ. multi-version concurrency control, MVCC) — это механизм управления параллельным доступом к данным в системах управления базами данных (СУБД) и файловых системах, при котором каждому читающему транзакции предоставляется «снимок» данных (snapshot) на определённый момент времени, а записывающие транзакции создают новые версии изменяемых объектов, не блокируя читающих. Основная цель MVCC — обеспечить высокую степень параллелизма и изоляцию транзакций без использования дорогостоящих блокировок на чтение.

Принцип работы

В основе многоверсионного управления лежит идея хранения нескольких версий одного и того же объекта данных (строки таблицы, документа, блока). Каждая версия помечается временной меткой или номером транзакции, которая её создала. Когда транзакция начинает чтение, система фиксирует её «время начала» и предоставляет доступ только к тем версиям, которые были созданы до этого момента и не были удалены (то есть являются «видимыми»). Записывающая транзакция, изменяя данные, не перезаписывает старую версию, а создаёт новую. Другие транзакции, начавшиеся раньше, продолжают видеть старую версию, а новые транзакции — новую. После завершения (коммита) записывающей транзакции её версия становится видимой для всех последующих транзакций. Если транзакция откатывается, её новые версии просто игнорируются и впоследствии удаляются сборщиком мусора.

Управление версиями

Существуют два основных подхода к хранению версий:

  • Хранение версий в основном пространстве таблицы (append-only). Каждая новая версия записывается как новая строка в той же таблице или в специальной структуре. Старые версии помечаются как неактивные. Этот метод используется, например, в PostgreSQL и InnoDB (MySQL).
  • Хранение версий в отдельном журнале (rollback segment, undo log). В основной таблице хранится только текущая версия, а старые — в специальном сегменте отката. При чтении система восстанавливает старую версию из журнала. Этот метод применяется в Oracle Database и Microsoft SQL Server (в режиме snapshot isolation).

Определение видимости версий

Система должна для каждой транзакции определить, какие версии данных ей «видны». Для этого используются:

  • Монотонно возрастающие идентификаторы транзакций (transaction IDs). Каждой транзакции присваивается уникальный номер. Версия считается видимой, если её идентификатор создателя меньше идентификатора читающей транзакции и не находится в списке активных транзакций на момент начала чтения.
  • Временные метки (timestamps). Используются системные часы или логические счётчики. Видимость определяется сравнением временных меток версий и транзакций.

Преимущества и недостатки

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

  • Высокая производительность чтения. Читающие транзакции никогда не блокируются записывающими. Это критически важно для систем с интенсивным чтением (OLAP, веб-приложения, отчёты).
  • Отсутствие взаимоблокировок (deadlocks) для операций чтения. Поскольку чтение не требует блокировок, классические deadlocks, связанные с ожиданием блокировки на чтение, не возникают.
  • Согласованное чтение (consistent read). Транзакция всегда видит целостный снимок данных на момент своего начала, что соответствует уровню изоляции «читаемое зафиксированное» (Read Committed) или «повторяемое чтение» (Repeatable Read) без дополнительных блокировок.
  • Устойчивость к отказам. В случае сбоя незавершённые транзакции легко откатываются путём удаления их версий, не затрагивая данные других транзакций.

Недостатки

  • Увеличение накладных расходов на хранение. Необходимость хранить множество версий данных приводит к росту объёма дискового пространства и памяти. Требуется эффективный сборщик мусора (vacuum, purge) для удаления устаревших версий.
  • Сложность реализации. MVCC требует тщательного управления версиями, временными метками и видимостью, что усложняет код СУБД и повышает риск ошибок.
  • Проблема «разрастания версий» (version bloat). При долгих транзакциях или высокой частоте обновлений количество старых версий может резко возрасти, замедляя чтение и сборку мусора.
  • Возможность аномалий. Некоторые уровни изоляции, основанные на MVCC (например, Snapshot Isolation), не предотвращают все виды аномалий, такие как «потерянное обновление» (lost update) или «запись по снимку» (write skew). Для их устранения требуются дополнительные механизмы (например, блокировки при конфликтах или сериализуемые снимки).

Применение в СУБД

MVCC является стандартным механизмом для большинства современных реляционных и нереляционных СУБД.

  • PostgreSQL. Одна из первых СУБД, полностью реализовавшая MVCC. Использует хранение версий в основной таблице (heap) с механизмом очистки (VACUUM). Поддерживает уровни изоляции Read Committed (по умолчанию) и Repeatable Read (Snapshot Isolation), а также Serializable Snapshot Isolation (SSI).
  • MySQL (InnoDB). Использует MVCC для поддержки уровней изоляции Read Committed и Repeatable Read. Версии хранятся в журнале отката (undo log). InnoDB также использует блокировки на уровне строк для предотвращения конфликтов записи.
  • Oracle Database. Реализует MVCC через сегменты отката (rollback segments). Обеспечивает уровень изоляции Read Committed по умолчанию и Serializable (Snapshot Isolation) по запросу. Oracle не блокирует чтение, даже при наличии блокировок записи.
  • Microsoft SQL Server. В версии 2005 года добавил поддержку Snapshot Isolation и Read Committed Snapshot Isolation (RCSI) на основе MVCC. Использует версионное хранилище (version store) в базе данных tempdb.
  • SQLite. Начиная с версии 3.0, использует MVCC для обеспечения изоляции транзакций. Версии хранятся в файле базы данных, а для чтения используется снимок.
  • Нереляционные СУБД. Многие NoSQL-системы, такие как MongoDB, Couchbase, Cassandra, также применяют MVCC для управления параллельным доступом и обеспечения согласованности.

Применение в файловых системах

MVCC применяется не только в СУБД, но и в некоторых файловых системах для обеспечения атомарности операций и версионирования файлов.

  • ZFS. Использует транзакционную модель на основе MVCC. Каждая операция записи создаёт новую версию блока данных, а старые версии остаются доступными до завершения транзакции. Это обеспечивает целостность данных при сбоях и позволяет реализовать снапшоты (snapshots) и клонирование.
  • Btrfs. Аналогично ZFS, использует копирование при записи (copy-on-write, CoW) и MVCC для управления версиями данных и метаданных. Поддерживает снапшоты и сжатие.
  • WAFL (NetApp). Файловая система, используемая в сетевых хранилищах NetApp, также основана на CoW и MVCC, что позволяет создавать мгновенные снапшоты.

Альтернативы

Основной альтернативой MVCC является блокирующее управление параллельным доступом (pessimistic concurrency control), при котором транзакции блокируют данные на время чтения или записи. Блокировки могут быть разделяемыми (shared, для чтения) и исключительными (exclusive, для записи). Этот подход проще в реализации, но значительно снижает параллелизм, особенно при интенсивном чтении. Другой альтернативой является оптимистическое управление параллельным доступом (optimistic concurrency control), при котором транзакции работают без блокировок, а при коммите проверяется, не изменили ли данные другие транзакции. В случае конфликта транзакция откатывается и повторяется.

Источники

  • Gray, J., & Reuter, A. (1992). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
  • Bernstein, P. A., Hadzilacos, V., & Goodman, N. (1987). Concurrency Control and Recovery in Database Systems. Addison-Wesley.
  • Hellerstein, J. M., Stonebraker, M., & Hamilton, J. (2007). Architecture of a Database System. Foundations and Trends in Databases.
  • Документация PostgreSQL: «MVCC» (глава 13).
  • Документация MySQL: «InnoDB Multi-Versioning».
  • Документация Oracle Database: «Concurrency and Transaction Management».
  • Документация Microsoft SQL Server: «Row Versioning-Based Isolation Levels».
  • Документация ZFS: «Transactional Semantics».

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →