¿Qué es un write concern (cometido de escritura) en MongoDB? ¿Qué es un read concern (cometido de lectura) en MongoDB?

Categoría
Descripción

Los cometidos de escritura y lectura son mecanismos de durabilidad que permiten asegurar la fiabilidad y calidad de los datos escritos y leídos. Son mecanismos complementarios, pero independientes entre sí. Se puede establecer un cometido de lectura sin cometido de escritura, un cometido de escritura sin posteriormente utilizar un cometido de lectura, o usar ambos.

¿Qué es el write concern? (Cometido de escritura)

El write concern, o cometido de escritura, es un mecanismo de reconocimiento que se puede añadir a las operaciones de escritura, y que lleva a una mejor durabilidad de los datos. Implica la comprobación de que la operación de escritura se haya propagado al número de nodos especificado en el write concern. Cuanto mayor sea su valor, mayor es la durabilidad de los datos, al asegurar que se ha escrito en una mayor cantidad de nodos.

El problema es que cuanto mayor sea la durabilidad exigida, mayor será el tiempo necesario en obtener esa garantía, puesto que será necesario esperar la confirmación de un mayor número de nodos. Existen varios niveles:

  • 0 - No se espera confirmación. Es suficiente con tener una conectividad con el conjunto y poder emitir el comando de escritura. Simplemente lanza la orden y no espera  a saber si se ha ejecutado correctamente. Es un método rápido pero inseguro.
  • 1 (valor por defecto) - Se espera únicamente la confirmación del nodo primario
  • >=2 - Se espera la confirmación del nodo primario y al menos uno de los secundarios
  • majority - Se espera la confirmación de una mayoría simple de nodos dentro del conjunto.Esta mayoría se obtiene dividiendo por 2 el número de nodos del conjunto y redondeando hacia arriba. Por ejemplo, en caso de un conjunto de 3 nodos, la mayoría simple sería 2.

Independientemente del nivel establecido en el write concern, MongoDB efectuará el replicado de los datos a todos los nodos. El write concern únicamente existe para que como desarrollador se pueda exigir una durabilidad de los datos y se pueda obtener una confirmación de que los datos se han llegado a escribir en el número de nodos indicado.

Existen también 2 opciones involucradas en el mecanismo de cometido de escritura:

  • wtimeout: <int>: establece el tiempo de espera necesario antes de marcar la operación como fallida en caso de que se demore la confirmación de escritura. Si este tiempo de espera se cumple y el concern se da como fallido, no quiere decir que la operación de escritura haya fallado, sino simplemente que la operación ha tardado más de lo esperado.
  • j: <true|false>: (j viene de journal) requiere que el nodo reciba la operación y la escriba en el fichero de transacciones antes de poder emitir la confirmación de escritura. A partir de MongoDB 3.2.6, el write concern majority implica el establecimiento de j a true. Mediante esta opción, incrementamos el nivel de durabilidad puesto que aseguramos no sólo que la operación de escritura ha llegado al nodo, sino también que esta operación ha sido escrita en el registro de transacciones. Si j se establece a false, o mongod se inicia sin registro de transacciones (journaling), entonces la confirmación se emitirá simplemente cuando el nodo almacene el dato en memoria.

Los comandos que trabajan con write concern son insert, update, delete y findAndModify. Para especificar el write concern, se puede indicar en el objeto de opciones de la operación. El nivel se indica como writeConcern.w. Por ejemplo:

 db.productos.insert({"nombre": "Tumbona de playa"}, { writeConcern: { w: 3, wtimeout: 1000}}

Especifica un write concern de nivel 3, lo cual exige que el dato se escriba en al menos 3 nodos del conjunto, con un tiempo de espera de 1000 milisegundos.

¿Qué es read concern? (Cometido de lectura)

Es el concepto complementario a write concern, que asegura la durabilidad de los datos en operaciones de lectura. Es un mecanismo que asegura que los datos leídos por la aplicación son fiables y realmente existen en todo el cluster.

Imaginemos un escenario en el que recibimos la confirmación de escritura por el nodo primario. Inmediatamente efectuamos una operación de lectura, el nodo devuelve el dato, pero éste falla antes de replicar la operación de escritura a los nodos secundarios. Sobre esta operación se efectuará un proceso de rollback en el momento que el nodo primario vuelva a estar disponible, por lo que ese dato realmente no existirá en el conjunto replicado. Es decir, la aplicación actualmente tiene un dato que no existe en el conjunto.

El read concern permite obtener unas mínimas garantías de que el dato que estamos leyendo es correcto y durable. Cuando se utiliza, únicamente devolverá datos cuya grabación haya sido confirmada por el número de nodos especificados en sus opciones. Se puede escoger entre devolver el dato más reciente que exista en el cluster, o el dato recibido por una mayoría de miembros en el cluster.

El hecho de que un documento no se considere correcto, no quiere decir necesariamente que se haya perdido, sino que en el momento de su lectura, no ha cumplido las condiciones necesarias de durabilidad para ser devuelto. Puede ser que la lectura se esté produciendo antes de que el dato haya sido propagado al número mínimo de miembros necesario, y por eso no se obtenga, pero en lecturas sucesivas sí puede aparecer.

Existen 4 modalidades de read concern:

  • local: devuelve el dato más reciente en el cluster. Cualquier dato que haya sido escrito en el nodo primario puede ser elegido para devolverse en el read concern local. Sin embargo, no se garantiza que este dato sea replicado a los miembros del conjunto en caso de fallo. Este es el nivel por defecto en las operaciones de lectura contra el nodo primario.
  • available: es el equivalente de local, pero cuando las operaciones de lectura se efectúan contra un nodo secundario.
  • majority: únicamente devuelve datos que hayan sido confirmados en una mayoría de nodos dentro del conjunto. El único escenario en el que un dato obtenido con majority no sea consistente, es cuando se produce un fallo en una mayoría de nodos del conjunto, y ese dato no ha sido escrito a ninguno de los nodos restantes.
  • linearizable: a partir de MongoDB 3.4, devuelve datos que hayan sido confirmados por una mayoría de nodos, pero permite al desarrollador establecer su propia funcionalidad.

Preferencia de lectura

Es un mecanismo que permite enrutar las operaciones de lectura hasta los nodos secundarios. Es una opción principalmente del driver que conecta con la base de datos, por lo que se debe consultar la documentación del mismo para conocer la forma de implementarlo.

Por defecto en un conjunto replicado, las operaciones de lectura/escritura se efectúan sobre el nodo primario. Con la preferencia de lectura, se puede obligar a obtener los datos de un nodo secundario. Existen 5 modos distintos de preferencia de lectura:

  • primary: es el modo por defecto. Enruta todas las operaciones de lectura al nodo primario únicamente.
  • primaryPreferred: enruta las operaciones de lectura al nodo primario, pero si el nodo primario no está disponible (por un fallo o por estar en un proceso de elecciones), la aplicación puede redirigir la lectura a un nodo secundario
  • secondary: enruta todas las operaciones de lectura únicamente a los nodos secundarios
  • secondaryPreferred: enruta todas las operaciones de lectura a los nodos secundarios, pero en caso de no haber ninguno disponible, las enruta al nodo primario
  • nearest: enruta las operaciones de lectura al nodo con una menor latencia desde el nodo solicitante, independientemente de que sea primario o secundario. Esto permite el soporte de operaciones de lectura geográficamente locales.

Siempre que se obtengan datos de nodos secundarios, puede darse la circunstancia de que las operaciones de lectura reciban datos que no sean actuales, por no haberse replicado en ese momento desde el nodo primario.