[recovery mode] Принципы работы OLTP-систем. Требования ACID
Руководитель курса BI-аналитика
Введение
Транзакция — достаточно обширное понятие, которое используется в разных сферах жизни. Существует банковская транзакция — это операция, которая состоит в переводе денежных средств с одного счёта на другой. Или бывает банкоматная транзакция — выдача денег либо проведение иной операции с помощью терминала. В юриспруденции понятию «транзакция» придается значение схожее со значением понятия «сделка», а в психологии — это факт коммуникации между людьми (трансакция).
Наконец, для информационных технологий «транзакция» — это последовательность (одна или несколько) операций по работе с данными. Чтобы организовать правильный обмен данными к транзакциям и транзакционным системам применяются некоторые требования, которые легли в основу архитектуры современных баз данных.
Чтобы подробно изучить эти требования, обратимся к простому бытовому примеру.
Атомарность
Предположим, мы переводим средства с одного банковского счета на другой. Эта операция состоит из нескольких действий: первое — начало транзакции в ходе которого устанавливается соединение между счетами, далее идёт снятие определенной суммы (например, 300 рублей) со счёта №1, потом — добавление этой же суммы на счёт №2 и стадия завершения в конце транзакции, которую рассмотрим чуть подробнее ниже. Представим себе ситуацию, по которой зачисление средств не прошло или выполнилось с ошибкой. В таком случае, необходимо вернуть средства на счёт №1. В этом заключается первое требование к транзакционным системам, которое называется атомарностью.
Атомарность (Atomicity) вкратце описывается принципом «всё, или ничего». Это означает, что каждая транзакция должна выполняться полностью или не выполняться совсем. У транзакции нет промежуточных состояний, т.е. она всегда является завершенной. У завершения транзакции есть 2 сценария: подтверждение (commit) и откат (rollback). Возвращаясь к случаю, когда средства сняты с банковского счета №1 и не поступили на счёт №2, в таком случае завершением транзакции станет rollback транзакции и возврат средств обратно на счёт №1. Если операции, входящие в транзакцию выполнены, происходит commit выполненных изменений.
Консистентность
После того как транзакция зафиксировала результаты и перевод средств с одного счёта на другой осуществлён, мы перевели нашу базу данных из одного состояния, в котором пользователь счета №1 был на 300 рублей богаче, а пользователь счёта №2 на 300 рублей беднее, в обратное состояние. При этом, деньги не появились из ниоткуда, т.е база внутри себя осталась согласованной или консистентной. Требование консистентности (Consistency) является вторым к транзакционным системам и логически вытекает из требования атомарности, т.е. каждая выполненная транзакция фиксирует только допустимые результаты. Если со счёта №1 снято 300 рублей, на счёт №2 не должно прийти 200 или 400 рублей, что также предусматривается требованиями консистентности. В этом смысле, данное требование также схоже с законом сохранения энергии в естественных науках.
Также требование консистентности подразумевает, что данные не будут принимать недопустимых значений. Например, средства на счету не принимают отрицательных значений.
У требования консистентности существует нюанс, которых связан со временем выполнения транзакции. Некоторые транзакции выполняются мгновенно, а выполнение некоторых может занимать от нескольких минут до нескольких часов. В течении выполнения транзакции система будет оставаться несогласованной. В этом смысле, гарантировать полное выполнение требования консистентности практически невозможно, можно только стремиться к этому.
Изолированность
При работе со счетами, обозначенными в нашем примере, может быть не один, а сразу несколько пользователей. А что, если таких пользователей будет несколько десятков или даже сотен?
В случае параллельного выполнения транзакций разными пользователями возникают различные проблемы. Например, если с того же счёта №1, на котором лежит 300 рублей, идёт параллельное выполнение 2-ух транзакций. По одной мы списываем 200 рублей, по другой — начисляем 200 рублей. Если во время выполнения начисления 200 рублей, списание не успело пройти, на счёте мы увидим 500 рублей. Первая транзакция в этом случае потеряется. Такая проблема называется потерянным обновлением.
Еще пример, мы списываем все 300 рублей с того же счёта №1. В этот момент другой пользователь запросил данные с этого счёта и увидел, что на нём осталось 0 рублей. Однако, мы откатили транзакцию по снятию 300 рублей и деньги вернулись на счёт. Получается, другой пользователь получил ошибочные данных о состоянии счёта №1. Это называется »грязным» чтением.
Еще варианты возникновения проблем при совместном выполнении транзакций лучше описываются на примере построения отчётов, и возникают, когда идут одновременные транзакции на чтение и обновление данных. Например, если один пользователь будет считать сумму совершенных покупок по счёту №1, а второй, в это же время, обновит данные по покупкам. Тогда результат чтения суммы покупок по счёту №1 будет неправильным, возникнет ошибка, называемая неповторяющимся чтением. В том же случае, если второй пользователь не обновит, а удалит или запишет дополнительные покупки по счёту №1, тогда первый пользователь получит ошибку фантомного чтения.
Чтобы избежать таких проблем с транзакциями, вводится требование на изолированность (Isolation) для других пользователей. Есть несколько уровней изоляции транзакций, но все они сводятся к блокировке действий одного пользователя, при выполнении изменения или чтения данных другим пользователем. Иногда изолированности транзакций добиваются не введением блокировок, а с помощью версифицирования. Проще говоря, пока записывающая транзакция не сделает commit изменений, остальные пользователи читают старую версию записи и не блокируются.
Более высокий уровень изолированности улучшает согласованность системы с одной стороны, но с другой стороны уменьшает количество параллельно выполняемых транзакций, т.е скорость системы. Поэтому соблюдение требования изолированности транзакционной системы всегда является «палкой о двух концах».
Устойчивость
Наконец, транзакционная система должна обладать устойчивостью (Durability). Это означает то, что если произошёл перевод 300 рублей с одного счёта на другой счёт, и операция прошла успешно, мы должны быть застрахованы от того, что никакие сбои или проблемы с оборудованием не повлияют на эту транзакцию. В итоге, если соединить первые буквы этих четырех требований к транзакционным системам, мы получаем акроним ACID, который можно схематично изобразить следующим образом (рис. 1).
Рисунок 1. ACID (схема)
Заключение
Таким образом, мы узнали что такое транзакция в разных смыслах значения этого понятия. Мы узнали из каких этапов состоит транзакция, какие сценарии завершения транзакции существуют и чем отличаются. Узнали какие требования к транзакционной системе предъявляют свойства атомарности, консистентности, изолированности и устойчивости транзакций.
Требования ACID являются фундаментальными основами устройства реляционных СУБД и обеспечивают наиболее надёжную и предсказуемую работу с данными.
На одном из модулей курса по BI-аналитике мы рассмотрим эти и другие принципы работы современных баз данных, способы взаимодействия и подключения к ним, а также язык запросов к данным SQL. По ссылке вы сможете более подробно узнать о курсе, а также зарегистрироваться на бесплатный пробный урок.