MongoDB предоставляет несколько различных способов выбора, как будет проходить запись в базу данных. Эти способы называются гарантии записи и охватывают все: от полного игнорирования всех ошибок до определения того, какие серверы должны подтвердить запись перед возвратом операции.
Когда для записи (например, с помощью MongoCollection::insert(), MongoCollection::update() и MongoCollection::remove()) задается параметр гарантий записи ("w"), драйвер отправляет запрос в MongoDB и piggy возвращает команду getLastError (GLE) одновременно с опцией гарантии записи. Сервер возвращает только в том случае, если условие гарантий записи прошло проверку, как выполненное или время ожидания запроса истекло (с параметром "wtimeout" по умолчанию установлено значение 10000 миллисекунд).
Несмотря на то, что время ожидания команды getLastError истекло, данные, скорее всего, будут записаны на основной сервер и реплицированы на все вторичные серверы, как только они его догонят.
Типичные причины возникновения превышения времени ожидания - указание записи о проблеме, которая требует подтверждения с большего количества серверов, чем доступно в данный момент.
При использовании подтвержденных записей и сбоя набора реплик, драйвер автоматически отключается от основного сервера, выдает исключение и пытается найти новый основной на следующей операции (ваше приложение должно решить, следует ли повторить операцию на новый основной сервер).
При использовании неподтвержденных записей (w=0) и при сбое набора реплик, драйвер не сможет узнать об изменении, поэтому он продолжит работу и молча прекратит запись.
Гарантии записи по умолчанию для MongoClient – 1: подтверждение операций записи.
Гарантии записи | Значение | Описание |
---|---|---|
w=0 | Не подтвержден | За записью не последует вызов GLE, поэтому она не проверяется ("выстрели и забудь") |
w=1 | Подтвержден | Запись будет подтверждена сервером (основной в конфигурации набора реплик) |
w=N | Набор реплик подтвержден | Запись будет подтверждена основным сервером и реплицирована на N-1 вторичных серверов. |
w=majority | Подтвержден большинством | Запись будет подтверждена большинством наборов реплик (включая основной). Это специальная зарезервированная строка. |
w=<tag set> | Набор меток для набора реплик подтвержден | Запись будет подтверждена всеми членами набора меток. |
j=true | Журналируемый | Запись будет подтверждена первичным сервером и журнал будет записан на диск |
Каждый из методов, вызывающих запись (MongoCollection::insert(), MongoCollection::update(), MongoCollection::remove() и MongoCollection::batchInsert()), позволяет использовать необязательный аргумент для отправки набора параметров в MongoDB сервер. С этим массивом опций вы можете установить гарантии записи, как показано в следующем примере:
Пример #1 Передача гарантий записи в запись
<?php
// Устанавливаем w=0 для insert:
$collection->insert($someDoc, array("w" => 0));
// Устанавливаем w=majority для update:
$collection->update($someDoc, $someUpdates, array("w" => "majority"));
// Устанавливаем w=5 и j=true для remove:
$collection->remove($someDoc, array("w" => 5, "j" => true));
// Устанавливаем w="AllDCs" для batchInsert:
$collection->batchInsert(array($someDoc1, $someDoc2), array("w" => "AllDCs"));
?>
Помимо установки гарантий записи для каждой операции в качестве аргумента опции, также можно установить гарантии записи по умолчанию различными способами.
Первый способ - через строку подключения. Строка подключения принимает параметры journal, w и wTimeoutMS:
Пример #2 Гарантии записи в строке подключения
<?php
$m = new MongoClient("mongodb://localhost/?journal=true&w=majority&wTimeoutMS=20000");
?>
Начиная с версии 1.5 драйвера также можно вызывать MongoDB::setWriteConcern() и MongoCollection::setWriteConcern(), чтобы установить гарантии записи по умолчанию для всех операций, созданных из этого конкретного объекта MongoDB или MongoCollection:
Пример #3 MongoDB::setWriteConcern и MongoCollection::setWriteConcern
<?php
$m = new MongoClient("mongodb://localhost/");
$d = $m->demoDb;
$c = $d->demoCollection;
// Устанавливаем w=3 на объекте базы данных с таймаутом 25000 мс
$d->setWriteConcern(3, 25000);
// Устанавливаем w=majority на объекте коллекции без изменения времени ожидания
$c->setWriteConcern("majority");
?>
Не требуя от сервера подтверждения записи, запись может быть выполнена очень быстро, но вы не будете знаеть, действительно ли запись удалась. Запись может завершиться неудачей по ряду причин: если есть проблемы с сетью, если сервер базы данных вышел из строя, или если запись была просто недействительной (например, запись в системную коллекцию или ошибки дублированного ключа).
При разработке всегда следует использовать подтвержденные записи (для защиты от непреднамеренных ошибок, таких как синтаксические ошибки, недопустимые операторы, ошибки дублирующихся ключей и т.д.). В производстве неподтвержденные записи могут использоваться для "незначительных" данных. Незначительные данные различаются в зависимости от приложения, но, как правило, это автоматические (вместо сгенерированных пользователем) данные, таких как отслеживание кликов или местоположения GPS, где вы можете получать тысячи записей в секунду.
Настоятельно рекомендуется выполнять подтвержденную запись в конце серии неподтвержденных записей. Это не приведет к слишком большим потерям производительности, но все же позволит вам отследить любые ошибки, которые могли произойти.
Пример #4 Неподтвержденные гарантии записи, сопровождаемые подтверждением записи
<?php
$collection->insert($someDoc, array("w" => 0));
$collection->update($criteria, $newObj, array("w" => 0));
$collection->insert($somethingElse, array("w" => 0));
try {
$collection->remove($something, array("w" => 1));
} catch(MongoCursorException $e) {
/* Обрабатываем исключение.. */
/* Здесь мы должны выполнить запросы find() по идентификаторам,
сгенерированным для $thingElse и $someDoc, чтобы убедиться,
что они записаны в базу данных, и попытаться выяснить, где в цепочке что-то произошло */
}
?>
Если последняя запись выдает исключение, вы будете знать, что есть проблема с вашей базой данных.
Этот тип операций записи гарантирует, что база данных приняла операцию записи, прежде чем вернуть успешное выполнение. Если запись не удалась, она выдаст исключение MongoCursorException с объяснением ошибки. Поведение MongoClient по умолчанию - подтверждение записи (w=1).
Можно указать, сколько членов набора реплик должно подтвердить запись (т.е. реплицировать ли ее) до того, как запись будет признана подтвержденной и операция вернет успешное выполнение.
Пример #5 Подтвержденные записи
<?php
// Принудительное подтверждение только от основного сервера
$collection->insert($doc, array("w" => 1));
// Принудительное подтверждение от основного и еще одного
// члена набора реплик
$collection->insert($doc, array("w" => 2));
// Принудительное подтверждение от основного и шести других
// членов набора реплик (вы, вероятно, никогда не должны делать так):
$collection->insert($doc, array("w" => 7));
?>
Имейте в виду, необходимо тщательно выбирать ваши гарантии записи. Если у вас есть набор реплик с 5 участниками, и вы выбираете гарантии записи 4, вы рискуете заблокировать запись навсегда, когда один из членов набора реплик выйдет из строя на техническое обслуживание или произойдет временное отключение сети.
Передача строкового значения для гарантий записи имеет особое значение (Набор меток для набора реплик подтвержден). Пожалуйста, будьте осторожны, НЕ используйте строковые значения для чисел (т.е. array("w" => "1")), так как он будет рассматриваться, как имя набора тегов.
Использование особой опции majority гарантий записи - это рекомендуемый способ записи, необходимый для выживания после апокалипсиса, поскольку он гарантирует, что большая часть вашего набора реплик будет иметь запись и, следовательно, будет гарантированно выдерживать все обычные сценарии подозрительных сбоев.
Пример #6 Записи, подтвержденные большинством
<?php
$collection->insert($someDoc, array("w" => "majority"));
?>
При подключении к реплике задайте гарантии записи по умолчанию только для того, чтобы основной сервер подтвердил запись. Однако существует окно 100 мс, пока запись не будет занесена в журнал и записана на диск. Можно принудительно записать запись в журнал перед подтверждением записи, установив опцию j:
Пример #7 Подтвержденные и журналируемые записи
Принудительное заполнение журнала
<?php
$options = array(
"w" => 1,
"j" => true,
);
try {
$collection->insert($document, $options);
} catch(MongoCursorException $e) {
/* обрабатываем исключение */
}
?>
Версия | Описание |
---|---|
1.3.0 | В MongoClient были введены по умолчанию подтвержденные записи. Устаревшим значением по умолчанию в Mongo были неподтвержденные записи. |
1.3.0 | Опция "safe" записи устарела и недоступна для нового класса MongoClient. Вместо этого используйте опцию "w". |