- PVSM.RU - https://www.pvsm.ru -
MongoDB — замечательная база данных, которая становится все популярнее в последнее время. Все больше людей с SQL опытом начинают её использовать, и один и первых вопросов, который у них возникает: MongoDB transactions? [1].
Если поверить ответам со stackoverflow, то все плохо.
MongoDB doesn't support complex multi-document transactions. If that is something you absolutely need it probably isn't a great fit for you.
If transactions are required, perhaps NoSQL is not for you. Time to go back to ACID relational databases.
MongoDB does a lot of things well, but transactions is not one of those things.
Но мы не поверим и реализуем полноценные транзакции (ACID* и lock-free). Ниже будет рассказ о том, как эти транзакции работают, а тем, кому не терпится посмотреть код — добро пожаловать на GitHub [2] (осторожно, java).
Durability обеспчивается ровно в той степени, в которой её обеспечивает хранилище.
В отличии от многих других NoSQL решений, MongoDB поддерживает compare-and-set. Именно поддержка CAS позволяет добавить ACID транзакции. Если вы используете любое другое NoSQL хранилище с поддержкой CAS (например, HBase, Project Voldemort или ZooKeeper), то описанный подход можно применить и там.
Что такое CAS
Это механизм, который гарантирует отказ в изменении объекта, если с момента последнего чтения объект был изменен другим клиентом. Знакомый всем пример - система контроля версий, которая откажет вам в коммите, если ваш коллега успел закомититься раньше.
Собственно все объекты, которые мы хотим изменять в транзакции должны быть под защитой CAS, это влияет на модель данных. Допустим мы моделируем работу банка, ниже приведена модель счета как с защитой, так и без неё, надеюсь из этого ясно как нужно изменить остальные.
Беззащитные | Подзащитные | |
Модель |
|
|
Изменение данных |
|
|
Далее, я не буду акцентировать внимание на том, что у объекта есть версия, и что любое изменение объекта проходит с учетом его версии, но это нужно помнить и понимать, что любое изменение объекта может вылетить с ошибкой из-за конкурентного доступа.
На самом деле добавление версии — это не все изменения, которые нужно провести над моделью, чтобы она поддерживала транзакции, полностью измененная модель выглядит так:
{
_id : ObjectId(".."),
version : 0,
value : {
name : "gov",
balance : 600
},
updated : null,
tx : null
}
Добавились поля — updated и tx. Это служебные данные, которые используются в процессе транзакции. По структуре updated совпадает с value, по смыслу — это измененная версия объекта, которая превратится в value, если транзакция пройдет; tx — это объект класса ObjectId — foreign key для _id объекта, представляющий транзакцию. Объект представляющий транзакцию так же находится под защитой CAS.
Объяснить алгоритм просто, объяснить его так, что его корректность была очевидна, сложнее; поэтому придется то, что некоторыми сущностями я буду оперировать до того, как их определю.
Ниже идут верные утверждения, определения и свойства из которых позже будет составлен алгоритм.
Чистое состояние описывает объект после успешной транзакции: value содержит данные, а upated и tx — null.
Грязное незакомиченное состояние описывает объект в момент транзакции, updated содержит новую версию, а tx — _id объекта представляющего транзакцию, этот объект существует.
Грязное закомиченное состояние описывает объект после успешной транзакции, но которя упала до того, как успела подчистить за собой, updated содержит новую версию, tx — _id объекта представляющего транзакцию, но сам объект уже удален.
Для тех кому теперь не очивидна корректность, домашнее задание — проверить, что выполняются все свойства и утверждения, а затем используя их доказать ACID ☺
Мы добавили в MongoDB транзакции. Но на самом деле это не панацея и у них есть ограничения, некоторые перечислены ниже, а некоторые в комментариях
.
В случае ошибки сервера мы действительно можем получить неконсистентное состоянии базы, но защищаемся от неконсистентного состояния, вызванного падением клиента в момент записи. Если риск второго больше первого, то используя транзакции мы все-равно повышаем надежность системы.
Автор: shai_xylyd
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/16694
Ссылки в тексте:
[1] MongoDB transactions?: http://stackoverflow.com/questions/2655251/mongodb-transactions
[2] GitHub: https://github.com/rystsov/mongodb-transaction-example
Нажмите здесь для печати.