Asuntos de Escritura (Write Concerns)

MongoDB proporciona diferentes maneras de seleccionar la duración de una escritura a la base de datos. Estas formas se llaman Asuntos de Escritura y lo abarcan todo: desde ignorar completamente todos los errores, a seleccionar específicamente qué servidores son necesarios para confirmar la escritura antes de devolver la operación.

Cuando una a escritura (como con MongoCollection::insert(), MongoCollection::update(), y MongoCollection::remove()) se le proporciona una opción de Asunto de Escritura ("w"), el controlador enviará la consulta a MongoDB y luego proseguirá con un comando getLastError (GLE) con la opción de Asunto de Escritura al mismo tiempo. El servidor solo devuelve cuando la condición de Asunto de Escritura se verifica que se cumple, o la consulta expira (controlado con la opción"wtimeout", 10000 milisegundos es lo predeterminado).

Advertencia

Incluso si un comando getLastError expira, los datos habrán sido escritos probablemente en el servidor primario y serán replicados a todos los secundarios una vez se hayan finalizado con ellos.

La típica razón para que una expiración ocurra es si se especifica un Asunto de Escritura que requiera confirmación de más servidores de los que estén disponibles en ese momento.

Cuando se usan escrituras reconocidas y el conjunto de réplica ha fallado, el controlador se desconectará automáticamente del primario, lanzando una excepción, e intentará encontrar un nuevo primario en la siguiente operación (una aplicación debe decidir si reintentar o no la operación en el nuevo primario).

Cuando se usan escrituras no reconocidas (w=0) y el conjunto de réplica ha fallado, no hay manera de que el controlador esté al tanto del campo, por lo que continuará y fallará en la escritura silenciosamente.

El Asunto de Escritura predeterminado para MongoClient es 1: operaciones de escritura reconocidas.

Asuntos de Escritura disponibles
Asunto de Escritura Significado Descripción
w=0 Sin reconocimiento A una escritura no le seguirá una llamada a GLE, por lo que no será verificada ("dispara y olvida")
w=1 Con reconocimiento El servidor reconocerá la escritura (el primario en una configuración de conjunto de réplica)
w=N Reconocimiento por parte del conjunto de réplica El servidor primario reconocerá la escritra, que será replicada a N-1 secundarios.
w=majority Reconociemiento por la mayoría La escritura será reconocia por la mayoría del conjunto de réplica (primario inclusive). Es un string reservado especial.
w=<tag set> Reconocimiento por parte del conjunto de etiquetas del conjunto de réplica La escritura será reconocida por miembros de conjunto de etiquetas completo
j=true Con diario El primario reconocerá la escritura y el diario será volcado a disco

Usar WriteConcerns

Cada método que causa escrituras (MongoCollection::insert(), MongoCollection::update(), MongoCollection::remove(), y MongoCollection::batchInsert()) permite un argumento opcional para enviar un conjunto de opciones al servidor de MongoDB. Con este array de opciones se puede establecer el WriteConcern como ilustra el siguiente ejemplo:

Ejemplo #1 Pasar un WriteConcern a una operación de escritura

<?php
// Establecer w=0 para insertar:
$colección->insert($someDoc, array("w" => 0));

// Establecer w=majority para acutalizar:
$colección->update($someDoc$someUpdates, array("w" => "majority"));

// Establecer w=5 y j=true para eliminar:
$colección->update($someDoc, array("w" => 5"j" => true));

// Establecer w="AllDCs" para batchInsert:
$colección->update(array($someDoc1$someDoc2), array("w" => "AllDCs"));
?>

Además de establecer WriteConcerns por operación como un argumento de opción, es también posible establecer un WriteConcern predeterminado de diferentes formas.

La primera forma es a través de la cadena de conexión. La cadena de conexión acpeta las opciones journal, w, y wTimeoutMS:

Ejemplo #2 WriteConcerns en cadena de conexión

<?php
$m 
= new MongoClient("mongodb://localhost/?journal=true&w=majority&wTimeoutMS=20000");
?>

Desde la versión 1.5 del controlador, también es posible llamar a MongoDB::setWriteConcern() y a MongoCollection::setWriteConcern() para establecer un WriteConcern predeterminado para todas las operaciones creadas desde ese objeto MongoDB o MongoCollection específico:

Ejemplo #3 MongoDB::setWriteConcern y MongoCollection::setWriteConcern

<?php
$m 
= new MongoClient("mongodb://localhost/");
$d $m->demoDb;
$c $d->demoCollection;

// Establecer w=3 en el objeto de base de datos con un tiempo de espera de 25000ms
$d->setWriteConcern(325000);

// Establecer w=majority en el objeto de colección sin cambiar el tiempo de espera
$c->setWriteConcern("majority");
?>

Escrituras no reconocidas

Al no requerir que el servidor reconozca las escrituras, estas se pueden realizar extremadamente rápido, pero no se sabrá si realmente han tenido éxito. Las escritura puede fallas por varias razones: si hay problemas de red, si un servidor de bases de datos falla, o si la escritura simplemente no era válida (p.ej., al escribir en una colección de sistema, o errores de clave duplicada).

Durante el desarrollo, siempre se deberían usar escrituras reconocidas (para evitar errores inadvertidos, tales como errores de sintaxis, operadores no válidos, errores de clave duplicada , etc.). En la producción, las escrituras no reconocidas se pueden usar para datos "no importantes". Estos varían según la aplicación, pero generalmente son datos automáticos (al contrario de generados por el usuario), como el rastreo de clics o ubicaciones GPS, donde se pueden obtener miles de registros por segundo.

Es muy recomendable realizar una escritura reconocida al final de una serie de escrituras no reconocidas. Esto no incurrirá en una penalización muy grande de redimiento, pero aún se puede capturar cualquier error que pudiera ocurrir.

Ejemplo #4 Asunto de escritura no reconocido, seguido de una escritura reconocida

<?php
$colección
->insert($documento, array("w" => 0));
$colección->update($criterios$nuevonObj, array("w" => 0));
$colección->insert($otraCosa, array("w" => 0));
try {
    
$colección->remove($something, array("w" => 1));
} catch(
MongoCursorException $e) {
    
/* Manejar la excepción... */
    /* Aquí se debería emitir consultas find() en los IDs generados para
    $otraCosa y $documento, para verificar que han sido escritos en la base de datos
    e intentar resolver dónde ocurrió algo en la serie. */
}
?>

Si la última escritura lanza una excepción, se sabrá que hay un problema en la base de datos.

Escrituras reconocidas

Este tipo de operaciones de escritura se asegura de que la base de datos ha aceptado la operación de escritura antes de indicar que ha tenido éxito. Si la escritura falla, lanzará una MongoCursorException con una explicación del fallo. El comportamiento predeterminado dee MongoClient es reconocer la escritura (w=1).

Es posible especificar cuántos miembros de un conjunto de réplica tienen que reconocer la escritura (esto es, tiene que replicarla) antes de que la escritura se estime como reconocida y la operación devuelve.

Ejemplo #5 Escrituras reconocidas

<?php
// Forzar el reconocimiento por parte del primario solamente
$colección->insert($doc, array("w" => 1));

// Forzar el reconocimiento por parte del primario, y otro miembro del
// conjunto de réplica
$colección->insert($doc, array("w" => 2));

// Forzar el reconocimiento por parte del primario, y otros seis miembros del
// conjunto de réplica (probablemente nunca debería hacer esto):
$colección->insert($doc, array("w" => 7));
?>

Recuerde seleccionar el Asunto de Escritura con cuidado. Si se tiene un conjunto de réplica con 5 miembros y se selecciona un Asunto de Escritura de 4, se corre el riesgo de bloquear la escritura para siempre cuando un miembro del conjunto de réplica se desconecte por matenimiento o por un corte temporal de la red.

Advertencia

El paso de un valor de tipo string al Asunto de Escritura posee un significado específico (Reconocimiento por parte del conjunto de etiquetas del conjunto de réplica). Tenga cuidado de NO usar valores de tipo string para números (esto es, array("w" => "1")) ya que serán tratados como el nombre de un conjunto de etiquetas.

Escrituras reconocidas por la mayoría

Usar la opción de Asunto de Escritura majority es la forma recomendada para escrituras que requieren sobrevidir al apocalipsis, ya que se asegurá de que la mayoría del conjunto de réplica tendrá la escritura y, por lo tanto, se garantizará que sobrevivirá a todos los escenarios de corte sospechosos usuales.

Ejemplo #6 Escritura reconocida por la mayoría

<?php
$colección
->insert($documento, array("w" => "majority"));
?>

Escrituras con diario

Al conectarse a un conjunto de réplica, el Asunto de Escritura predeterminado es hacer que solamente el servidor primario reconozca al escritura. Hay, sin embargo, una ventata de 100 ms hasta que la escritura se escriba en el diario y sea volcada al disco. Es posible forzar a que la escritura sea escrita en el diario antes de que sea reconocia estableicendo la opción j:

Ejemplo #7 Escritura reconocida y esctrita en el diario

Forzar el volcado del diatio

<?php
$opciones 
= array(
    
"w" => 1,
    
"j" => true,
);
try {
    
$colección->insert($documento$opciones);
} catch(
MongoCursorException $e) {
    
/* manejar la excpeción */
}
?>

Historial de cambios

Versión Descripción
1.3.0 Se introdujo MongoClient, cuyo comportamiento predeterminado es reconocer escrituras. La obsoleta Mongo no reconoce las escrituras de forma predeterminada.
1.3.0 La opción de escritura "safe" ahora es obsoleta y no está disponible con la nueva clase MongoClient. Use la opción "w" en su lugar.