Архитектура MongoDb. Часть 2. Модель хранения, обновления и транзакции в MongoDb

Рубрика:

Продолжение. Начало Часть 1. Отличие от СУБД, обработка запросов в MongoDb

Модель хранения

Написанный на C++, MongoDB использует файл карты памяти, который непосредственно отображает дисковый файл данных в байтовый массив в памяти, где логика доступа к данным реализована с использованием арифметики указателей. Каждая коллекция документов хранится в одном файле пространства имен (который содержит информацию метаданных), также как несколько непрерывных файлов данных (с размером, который увеличивается по экспоненте или удваивается).

MongoDB storage model, модель хранения MongoDB

Структура данных широко использует двунаправленно связанный список. Каждая коллекция данных организована в связанном списке степеней, каждая из которых представляет непрерывное дисковое пространство. Каждая степень указывает на голову/хвост другого связанного списка документов. Каждый документ содержит связанный список к другим документам, к тому же актуальные данные закодированы в формате BSON.

Модификация данных происходит на месте. В случае, если модификация увеличивает размер записи вне его первоначально выделенного места, вся запись будет перемещена в бОльшую область с несколькими дополнительными байтами. Дополнительные байты используются в качестве буфера роста так, чтобы будущее расширение не требовало повторного перемещения данных. Количество дополнения динамически корректируется под коллекцию на основе ее статистики модификации. С другой стороны, место, занятое исходным документом, будет свободно. Это отслеживается в списке свободного места различных размеров.

Таким образом, можно предположить, что в течение долгого времени будут образовываться дыры, поскольку объекты создаются, удаляются или изменяются, эта фрагментация повредит производительности, так как меньше данных будут читаться/записываться на один дисковый ввод-вывод. Поэтому, мы должны периодически выполнять  команду "compact", которая копирует данные в непрерывное пространство. Эта "компактная" работа является исключительной операцией и должна быть сделана оффлайн. Обычно это делается во время Replica Set, выводя каждый элемент в оффлайн по одному, чтобы реализовать эту "компактность".

Индекс реализован как B-дерево. Каждый узел B-дерева содержит определенное число ключей (в этом узле), а также указатели на левые дочерние узлы B-дерева каждого ключа.

Обновление данных и Транзакции

Чтобы обновить существующий документ, мы можем сделать следующее:

var p1 = db.person.findone({lastname:"Ho"})
p1["address"] = "San Jose"
db.person.save(p1)

# Do the same in one command
db.person.update({lastname:"Ho"},
{$set:{address:"San Jose"}},
false,
true) 

Запись по умолчанию не ожидает. Существуют различные опции ожидания, клиенту можно определить, какие условия должны быть для ожидания перед возвратами вызова (этого можно достигнуть последующим вызовом "getlasterror"), например, где на диске сохранены изменения, или были ли распространены изменения в достаточном количестве элементов в Replica Set. MongoDb также предоставляет усложненный способ присвоения тегов элементам Replica Set, чтобы отразить их физическую топологию так, чтобы специализированная политика записи для каждого набора могла быть сделана на основе их требования надежности.

В СУБД "Сериализуемость" - крайне фундаментальное понятие о конечном результате параллельного выполнения единиц работы, эквивалентно тому, как будто эти единицы работы - это организация в некотором порядке последовательного выполнения (по одному в один момент времени). Поэтому каждый клиент может обращаться, как будто БД исключительно доступна. Базовая реализация сервера БД часто использует LOCK'и или Мультиверсии для обеспечения изоляции. Однако, это понятие не доступно в MongoDb (а также многих других NOSQL).

В MongoDb каждые данные, которые вы считываете, должны быть обработаны как снимок прошлого, что означает, что к тому времени, когда на него смотрите, эти данные могут быть изменены в БД. Поэтому, если вы делаете модификацию на основе некоторых ранее считанных данных, ко времени отправки запроса о модификации, условие, на котором она основана, может быть изменено. Если это не приемлемо для требования непротиворечивости приложения, возможно вам нужно будет подтвердить условие в то время, когда вы запрашиваете модификацию (т.е. должен быть сделан "conditional_modify").

В соответствии с этой схемой, "условие" прикреплено вместе с запросом модификации так, чтобы сервер БД мог проверить условие прежде, чем применить модификацию. (конечно, проверка условия и модификация должны быть атомарными, таким образом, в промежутке не может произойти никакого обновления). В MongoDb это может быть достигнуто вызовом "findAndModify".

var account = db.bank.findone({id:1234})
var old_bal = account['balance']
var new_bal = old_bal + fund

# Pre-condition is specified in search criteria
db.bank.findAndModify({id:1234, balance:old_bal},
{$set: {balance: new_bal}})

# Check if the prev command successfully
var success =
db.runCommand({getlasterror:1,j:true})

if (!success) {
#retry_from_beginning
}

Понятие "транзакции" в MongoDb также отсутствует. В то время как MongoDb гарантируют, что каждый документ будет атомарно изменен (таким образом, никакое частичное обновление в документе не произойдет), но если обновление изменяет многие документы, то нет никакой гарантии атомарности по документам.

Поэтому в обязанности разработчиков приложений реализовать атомарность мультиобновления по многим документам. Мы описываем общий шаблон разработки для достижения этого. Этот метод не специфичен для MongoDb и применим к другому хранилищу NOSQL, которое может, по крайней мере, гарантировать атомарность на единственном уровне записи.

Основная идея состоит в том, чтобы сначала создать отдельный документ (названный транзакцией), который соединяет все документы, которые требуется изменить. Затем создаете обратную ссылку из каждого изменяемого документа, назад к транзакции. Тщательно разработав последовательность обновления в документах и транзакции, вы можете достигнуть атомарности изменения многих документов.

Транзакции в MongoDB

На веб-сайте MongoDB также описан подобный метод на основе того же понятия, но реализация немного отличается. 

Читайте далее:

Часть 3. Модель репликации MongoDB

Часть 4. Шардинг, Map/Reduce в MongoDb

Автор: 
Ricky Ho, http://horicky.blogspot.com/2012/04/mongodb-architecture.html