Принципы ACID
Принципы ACID — это набор требований к транзакционной системе (например, к системе управления базами данных), гарантирующий надёжность и предсказуемость обработки транзакций. Акроним ACID расшифровывается как Atomicity (Атомарность), Consistency (Согласованность), Isolation (Изолированность) и Durability (Долговечность). Эти принципы являются фундаментальными для обеспечения целостности данных в условиях многопользовательского доступа и возможных сбоев.
История возникновения
Концепция ACID была сформулирована в начале 1980-х годов как ответ на потребность в формальном определении свойств транзакций в реляционных базах данных. Термин впервые ввёл в 1983 году Андреас Ройтер (Andreas Reuter) в соавторстве с Тео Хердером (Theo Härder) в статье «Принципы построения надёжных систем баз данных» (Principles of Transaction-Oriented Database Recovery). До этого в индустрии использовались разрозненные подходы к обеспечению надёжности, такие как двухфазная фиксация (two-phase commit) и журналирование изменений (write-ahead logging). ACID систематизировал эти практики в единый стандарт, который лёг в основу большинства промышленных СУБД (Oracle, Microsoft SQL Server, PostgreSQL, MySQL с InnoDB).
Определение транзакции
Транзакция — это логически неделимая последовательность операций над данными (чтение, запись, удаление, изменение), которая переводит базу данных из одного согласованного состояния в другое. Транзакция начинается оператором BEGIN TRANSACTION (или аналогичным) и завершается оператором COMMIT (успешное завершение, фиксация изменений) или ROLLBACK (откат, отмена всех изменений, выполненных в рамках транзакции).
Атомарность (Atomicity)
Атомарность гарантирует, что транзакция выполняется полностью или не выполняется вовсе (принцип «всё или ничего»). Если в процессе выполнения транзакции происходит сбой (отказ оборудования, ошибка программного обеспечения, нарушение целостности), система должна откатить все уже выполненные частичные изменения, как если бы транзакция никогда не начиналась. Если же транзакция завершается успешно, все её изменения становятся постоянными и видимыми для других транзакций.
Пример: Перевод денег с одного банковского счёта на другой. Атомарность гарантирует, что если списание со счёта А прошло успешно, а зачисление на счёт Б не удалось, то вся операция откатится, и деньги не пропадут.
Механизмы реализации:
- Журнал упреждающей записи (Write-Ahead Logging, WAL): Все изменения сначала записываются в журнал, и только после этого — в основную область данных. При сбое система может восстановить состояние по журналу.
- Теневые страницы (Shadow Paging): Создаётся копия страницы данных, изменения вносятся в копию, а затем указатель на страницу атомарно переключается на новую копию.
- Откат (Rollback): Использование отменяющих записей (undo logs) для возврата данных к исходному состоянию.
Согласованность (Consistency)
Согласованность гарантирует, что транзакция переводит базу данных из одного корректного состояния в другое корректное состояние. Это означает, что до и после выполнения транзакции все данные должны удовлетворять всем заданным ограничениям целостности: первичным ключам, внешним ключам, уникальным индексам, проверочным условиям (CHECK constraints), триггерам и бизнес-правилам, определённым на уровне схемы базы данных.
Важное уточнение: Согласованность — это свойство не только системы, но и приложения. Система гарантирует, что в случае сбоя она не позволит нарушить явно заданные ограничения (например, уникальность). Однако логическую корректность данных (например, что сумма дебета равна сумме кредита) должно обеспечивать приложение, записывая правильные данные.
Пример: В таблице «Заказы» есть внешний ключ на таблицу «Клиенты». Согласованность гарантирует, что нельзя создать заказ для несуществующего клиента. Если транзакция пытается это сделать, она будет отклонена.
Механизмы реализации:
- Декларативные ограничения (constraints) на уровне схемы.
- Триггеры, проверяющие бизнес-правила.
- Атомарность и изолированность как косвенные гаранты согласованности.
Изолированность (Isolation)
Изолированность гарантирует, что параллельно выполняющиеся транзакции не влияют друг на друга. Каждая транзакция должна выполняться так, как если бы она была единственной в системе, даже если на самом деле их много. Результат параллельного выполнения набора транзакций должен быть эквивалентен результату их последовательного выполнения в некотором порядке (сериализуемость).
На практике полная изолированность (сериализуемость) снижает производительность, поэтому в СУБД реализованы различные уровни изолированности, ослабляющие требования в обмен на скорость.
Уровни изолированности (по стандарту SQL)
- Read Uncommitted (Чтение незафиксированных данных): Самый низкий уровень. Транзакция может читать данные, изменённые другими транзакциями, которые ещё не зафиксированы («грязное чтение»). Практически не используется в серьёзных системах.
- Read Committed (Чтение зафиксированных данных): Уровень по умолчанию в большинстве СУБД (PostgreSQL, Oracle, SQL Server). Гарантирует, что транзакция видит только зафиксированные данные. «Грязное чтение» невозможно, но возможны «неповторяющееся чтение» (повторное чтение той же строки даёт другой результат) и «фантомное чтение» (повторное выполнение запроса возвращает новые строки, добавленные другой транзакцией).
- Repeatable Read (Повторяемость чтения): Гарантирует, что если транзакция прочитала строку, то при повторном чтении она получит те же данные (строки не могут быть изменены или удалены другими транзакциями, пока текущая активна). Однако возможны «фантомные чтения».
- Serializable (Сериализуемый): Самый высокий уровень. Полностью имитирует последовательное выполнение транзакций. Исключает все виды аномалий (грязное, неповторяющееся, фантомное чтение, потерю обновления). Обычно реализуется через блокировки или оптимистичное управление параллелизмом (MVCC с проверкой конфликтов).
Аномалии параллельного доступа
- Грязное чтение (Dirty Read): Чтение данных, изменённых незафиксированной транзакцией.
- Неповторяющееся чтение (Non-Repeatable Read): Разные результаты при повторном чтении одной и той же строки в рамках одной транзакции.
- Фантомное чтение (Phantom Read): Появление новых строк, удовлетворяющих условию запроса, при повторном выполнении запроса.
- Потерянное обновление (Lost Update): Две транзакции одновременно читают и изменяют одну и ту же строку, и одно из изменений теряется.
Механизмы реализации:
- Блокировки (Locks): Пессимистичный подход. Транзакция блокирует данные на время своей работы. Различают блокировки на чтение (shared lock) и на запись (exclusive lock).
- Многоверсионность (MVCC, Multi-Version Concurrency Control): Оптимистичный подход. Каждая транзакция работает со снимком данных (snapshot) на момент её начала. Изменения вносятся в новые версии строк, не затрагивая старые. Это позволяет читателям не блокировать писателей и наоборот. Используется в PostgreSQL, Oracle, MySQL с InnoDB.
Долговечность (Durability)
Долговечность гарантирует, что после успешного завершения транзакции (выполнения COMMIT) все её изменения сохраняются в системе постоянно и не могут быть отменены даже в случае немедленного сбоя питания, отказа оборудования или программного сбоя. Зафиксированные данные должны быть восстановлены системой при следующем запуске.
Пример: После успешного подтверждения перевода денег и выдачи чека, даже если сервер сразу выключится, при повторном включении сумма перевода должна быть зафиксирована на обоих счетах.
Механизмы реализации:
- Журналирование (Write-Ahead Logging): Самая распространённая техника. Запись о фиксации транзакции (
COMMITrecord) записывается в журнал на постоянный носитель (диск). Только после этого управление возвращается приложению. При сбое система воспроизводит (replay) все зафиксированные транзакции из журнала. - Резервное копирование: Регулярное создание копий базы данных.
- Репликация: Синхронное или асинхронное копирование данных на другой сервер.
- Использование энергонезависимой памяти (NVRAM, SSD): Современные системы используют SSD с конденсаторами для гарантии записи данных при внезапном отключении питания.
Критика и альтернативы
В начале XXI века, с развитием распределённых систем и NoSQL-баз данных, принципы ACID подверглись критике за излишнюю жёсткость, которая ограничивает масштабируемость и доступность в распределённых средах. В ответ была предложена теорема CAP (Брюэр, 2000), утверждающая, что в распределённой системе одновременно можно обеспечить только два из трёх свойств: согласованность (Consistency), доступность (Availability) и устойчивость к разделению (Partition tolerance).
Для систем, где высокая доступность и масштабируемость важнее строгой согласованности, была разработана модель BASE (Basically Available, Soft state, Eventual consistency — «в основном доступна, мягкое состояние, конечная согласованность»). Она жертвует немедленной согласованностью в пользу доступности, гарантируя, что данные в конечном итоге придут к согласованному состоянию.
Тем не менее, для традиционных OLTP-систем (онлайн-обработка транзакций), таких как банковские системы, бухгалтерский учёт, системы бронирования, принципы ACID остаются обязательным стандартом.
Источники
- Härder, T., Reuter, A. (1983). Principles of Transaction-Oriented Database Recovery. ACM Computing Surveys, 15(4), 287-317.
- Gray, J., Reuter, A. (1993). Transaction Processing: Concepts and Techniques. Morgan Kaufmann.
- Date, C. J. (2003). An Introduction to Database Systems (8th ed.). Addison-Wesley.
- Bernstein, P. A., Hadzilacos, V., Goodman, N. (1987). Concurrency Control and Recovery in Database Systems. Addison-Wesley.
- Gilbert, S., Lynch, N. (2002). Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services. ACM SIGACT News, 33(2), 51-59.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →