¿A qué nivel bloquea MongoDB las escrituras? (o: ¿qué significa “por conexión”?

En la documentación de mongodb, dice:

A partir de la versión 2.2, MongoDB implementa lockings por base de datos para la mayoría de las operaciones de lectura y escritura. Algunas operaciones globales, generalmente operaciones de corta vida que involucran múltiples bases de datos, aún requieren un locking global de “instancia” global. Antes de 2.2, solo hay un locking “global” por instancia de mongod.

¿Esto significa que en la situación en la que tengo, por ejemplo, 3 conexiones con mongodb: // localhost / test de diferentes aplicaciones que se ejecutan en la red, solo una podría estar escribiendo a la vez? ¿O es solo por conexión?

IOW: ¿Es por conexión o la base de datos completa / de prueba está bloqueada mientras se escribe?

No es por conexión, es por mongod . En otras palabras, el locking existirá en todas las conexiones a la base de datos de test en ese servidor.

También es un locking de lectura / escritura, por lo que si se produce una escritura, entonces debe esperar una lectura; de lo contrario, ¿cómo puede MongoDB saber que es una lectura consistente?

Sin embargo, debo mencionar que los lockings MongoDB son muy diferentes a los lockings SQL / transaccionales normales que se obtienen y normalmente se mantendrá un locking de aproximadamente un microsegundo entre las actualizaciones promedio.

MongoDB Locking es diferente

Bloquear en MongoDB no funciona como bloquear un RDBMS, por lo que un poco de explicación está en orden. En versiones anteriores de MongoDB, existía un único locking global de lector / escritor. Comenzando con MongoDB 2.2, hay un pestillo de lector / escritor para cada base de datos.

El pestillo lector-escritor

El pestillo es de lector múltiple, escritor único y codicioso para el escritor. Esto significa que:

  • Puede haber un número ilimitado de lectores simultáneos en una base de datos
  • Solo puede haber un escritor a la vez en cualquier colección en cualquier base de datos (más sobre esto en un poco)
  • Los escritores bloquean a los lectores
  • Por “escritor-codicioso”, quiero decir que una vez que una solicitud de escritura entra, todos los lectores están bloqueados hasta que la escritura se complete (más sobre esto más adelante)

Tenga en cuenta que llamo a esto un “pestillo” en lugar de un “locking”. Esto se debe a que es liviano, y en un esquema diseñado correctamente, el locking de escritura se mantiene en el orden de una docena de microsegundos. Consulte aquí para obtener más información sobre el locking de lectores y escritores.

En MongoDB puede ejecutar tantas consultas simultáneas como desee: siempre que los datos relevantes estén en la RAM, todos se satisfarán sin conflictos de locking.

Actualizaciones del documento atómico

Recuerde que en MongoDB el nivel de transacción es un documento único. Todas las actualizaciones de un solo documento son atómicas. MongoDB logra esto sujetando el pestillo de escritura solo durante el tiempo necesario para actualizar un solo documento en la RAM. Si hay alguna operación de ejecución lenta (en particular, si un documento o una entrada de índice necesita ser localizada desde el disco), entonces esa operación producirá el locking de escritura. Cuando la operación cede el enganche, la siguiente operación en cola puede continuar.

Esto significa que las escrituras en todos los documentos dentro de una única base de datos se serializan. Esto puede ser un problema si tiene un diseño de esquema deficiente, y sus escrituras toman mucho tiempo, pero en un esquema diseñado correctamente, el locking no es un problema.

Escritor-Codicioso

Algunas palabras más sobre ser escritor codicioso:

Solo un escritor puede mantener el seguro al mismo tiempo; múltiples lectores pueden mantener el seguro a la vez. En una implementación ingenua, los escritores podrían morir de hambre indefinidamente si hubiera un solo lector en funcionamiento. Para evitar esto, en la implementación de MongoDB, una vez que un hilo único realiza una solicitud de escritura para un pestillo en particular

  • Todos los lectores subsiguientes que necesiten ese pestillo bloquearán
  • Ese escritor esperará hasta que todos los lectores actuales hayan terminado
  • El escritor adquirirá el pestillo de escritura, hará su trabajo y luego liberará el pestillo de escritura
  • Todos los lectores en cola procederán ahora

El comportamiento real es complejo, ya que este comportamiento codicioso del escritor interactúa con ceder de maneras que pueden no ser obvias. Recuerde que, comenzando con la versión 2.2, hay un pestillo separado para cada base de datos, por lo que escribe en cualquier colección en la base de datos ‘A’ adquirirá un pestillo separado que escribe en cualquier colección en la base de datos ‘B’.

Preguntás especificas

En cuanto a las preguntas específicas:

  • El kernel de MongoDB mantiene lockings (en realidad, pestillos) solo durante el tiempo necesario para actualizar un solo documento
  • Si tiene múltiples conexiones entrando a MongoDB, y cada una de ellas está realizando una serie de escrituras, el enganche se llevará a cabo por base de datos por el tiempo que tarde en completar esa escritura.
  • Se intercalarán múltiples conexiones en la realización de escrituras (actualización / inserción / eliminación)

Si bien esto parece ser un gran problema de rendimiento, en la práctica no desacelera las cosas. Con un esquema adecuadamente diseñado y una carga de trabajo típica, MongoDB saturará la capacidad de E / S del disco, incluso para una SSD, antes de que el porcentaje de locking en cualquier base de datos supere el 50%.

El clúster de MongoDB de mayor capacidad del que tengo conocimiento actualmente realiza 2 millones de escrituras por segundo.

Mongo 3.0 ahora es compatible con el locking de nivel de colección.

Además de esto, ahora Mongo creó una API que permite crear un motor de almacenamiento. Mongo 3.0 viene con 2 motores de almacenamiento:

  1. MMAPv1 : el motor de almacenamiento predeterminado y el único uso en las versiones anteriores. Viene con el locking de nivel de colección.
  2. WiredTiger : el nuevo motor de almacenamiento, viene con locking y compresión a nivel de documento. (Solo disponible para la versión de 64 bits)

Notas de la versión de MongoDB 3.0

WiredTiger

Sé que la pregunta es bastante antigua, pero aún algunas personas están confundidas …

A partir de MongoDB 3.0, el motor de almacenamiento WiredTiger (que usa concurrencia a nivel de documento ) está disponible en las comstackciones de 64 bits.

WiredTiger utiliza control de concurrencia a nivel de documento para operaciones de escritura. Como resultado, varios clientes pueden modificar diferentes documentos de una colección al mismo tiempo.

Para la mayoría de las operaciones de lectura y escritura, WiredTiger utiliza un control de concurrencia optimista. WiredTiger usa solo lockings de bash en los niveles global, de base de datos y de recolección. Cuando el motor de almacenamiento detecta conflictos entre dos operaciones, se generará un conflicto de escritura que hará que MongoDB intente de forma transparente esa operación.

Algunas operaciones globales, generalmente operaciones de corta duración que involucran múltiples bases de datos, aún requieren un locking global “de toda la instancia”. Algunas otras operaciones, como eliminar una colección, aún requieren un locking de base de datos exclusivo.

Concurrencia de nivel de documento