Docs Menu
Docs Home
/
Manual de base de datos
/

Consideraciones de Producción

En la página siguiente se enumeran algunas consideraciones de producción para la ejecución de transacciones. Estas se aplican tanto si se ejecutan transacciones en conjuntos de réplicas como en clústeres fragmentados. Para ejecutar transacciones en clústeres fragmentados, consulte también Consideraciones de producción (clústeres fragmentados) para obtener consideraciones adicionales específicas de los clústeres fragmentados.

  • Las implementaciones autónomas de MongoDB no admiten transacciones. Para usar transacciones, la implementación debe ser un set de réplicas de varios nodos.

  • MongoDB admite transacciones multi-documento en sets de réplicas.

  • Las transacciones distribuidas agregan soporte para transacciones multi-documento en clústeres particionados e incorporan el soporte existente para transacciones multi-documento en sets de réplicas.

Nota

Transacciones distribuidas y transacciones multi-documento

Los dos términos son sinónimos. Las transacciones distribuidas se refieren a transacciones multi-documento en clústeres particionados y sets de réplicas. Las transacciones multi-documento (ya sea en clústeres fragmentados o en sets de réplicas) también se conocen como “transacciones distribuidas”.

Para utilizar transacciones, la featureCompatibilityVersion de todos los miembros de la implementación debe ser al menos:

Implementación
Mínimo featureCompatibilityVersion

Set de réplicas

4.0

Clúster fragmentado

4.2

Para comprobar la compatibilidad de características entre versiones de un nodo, conéctese al nodo y ejecute el siguiente comando:

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

Para obtener más información, consulte la página de referencia setFeatureCompatibilityVersion.

Nota

Para configurar la duración máxima de las transacciones en MongoDB Atlas, consulta Configurar la duración de la transacción en la documentación de Atlas.

Por defecto, una transacción debe tener un tiempo de ejecución inferior a un minuto. Puedes modificar este límite con transactionLifetimeLimitSeconds para las instancias mongod. Para los clústeres particionados, el parámetro debe modificarse para todos los nodos del set de réplicas de particiones. Las transacciones que superen este límite se consideran caducadas y serán abortadas por un proceso de limpieza periódico.

Para clústeres particionados, también puedes especificar un límite de maxTimeMS en commitTransaction. Para obtener más información, consulta Límite de tiempo de las transacciones de clústeres particionados.

MongoDB crea tantas entradas de oplog como sean necesarias para encapsular todas las operaciones de escritura en una transacción, en lugar de una sola entrada para todas las operaciones de escritura en la transacción. Esto remueve el límite de tamaño total de 16 MB para una transacción impuesto por la entrada única del oplog para todas sus operaciones de escritura. Aunque se remueva el límite de tamaño total, cada entrada del oplog todavía debe estar dentro del límite de tamaño del documento BSON de 16 MB.

Para evitar que la presión de la caché de almacenamiento afecte negativamente el rendimiento:

  • Cuando abandonas una transacción, abórtala.

  • Cuando se produzca un error durante la operación individual en la transacción, aborta y vuelve a intentar la transacción.

El valor transactionLifetimeLimitSeconds también garantiza que las transacciones caducadas se anulen periódicamente para aliviar la presión de la caché de almacenamiento.

Nota

Si tienes una transacción no confirmada que causa una presión excesiva en la caché de WiredTiger, la transacción se aborta y devuelve un error de conflicto de escritura.

Si una transacción es demasiado grande para caber en la caché de WiredTiger, la transacción se anula y devuelve un error TransactionTooLargeForCache.

No puedes ejecutar transacciones en un clúster que tenga una partición con writeConcernMajorityJournalDefault configurado en false (como una partición con un nodo votante que utiliza el motor de almacenamiento en memoria).

No puedes cambiar una clave de fragmentación mediante una transacción si el set de réplicas tiene un árbitro. Los árbitros no pueden participar en las operaciones de datos requeridas para las transacciones de múltiples fragmentos.

Las transacciones cuyas operaciones de escritura abarcan varios fragmentos generarán un error y se abortarán si alguna operación de transacción lee o escribe en una partición que contiene un árbitro.

Por defecto, las transacciones esperan hasta 5 milisegundos para adquirir los bloqueos requeridos por las operaciones en la transacción. Si la transacción no puede adquirir sus bloqueos requeridos en los 5 milisegundos, la transacción se cancela.

Las transacciones liberan todos los bloqueos al abortar o confirmar.

Tip

Al crear o descartar una colección inmediatamente antes de iniciar una transacción, si se accede a la colección dentro de la transacción, realice la operación de creación o descarte con el nivel de confirmación de escritura "majority" para asegurarse de que la transacción pueda adquirir los bloqueos necesarios.

Nota

Los clústeres MongoDB Atlas restringen el uso del comando setParameter. Para obtener más información, consulta Comandos no admitidos en Atlas en la documentación de Atlas.

Para modificar los parámetros del clúster de Atlas, ponte en contacto con el Soporte de Atlas.

Puedes utilizar el parámetro maxTransactionLockRequestTimeoutMillis para ajustar cuánto tiempo esperan las transacciones para adquirir bloqueos. El aumento de maxTransactionLockRequestTimeoutMillis permite que las operaciones de las transacciones esperen el tiempo especificado para adquirir los bloqueos necesarios. Esto puede ayudar a obviar abortos de transacciones en adquisiciones de bloqueos concurrentes momentáneas, como operaciones rápidas de metadatos. Sin embargo, esto podría demorar el aborto de las operaciones de transacciones en estado de bloqueo.

También puedes usar el tiempo de espera específico de la operación si estableces maxTransactionLockRequestTimeoutMillis en -1.

Si hay una transacción multi-documento en curso, nuevas operaciones DDL que afectan a las mismas bases de datos o colecciones esperan detrás de la transacción. Mientras existan estas operaciones DDL pendientes, las nuevas transacciones que accedan a las mismas bases de datos o colecciones que las operaciones DDL pendientes no podrán obtener los bloqueos necesarios y se anularán después de esperar maxTransactionLockRequestTimeoutMillis. Además, las nuevas operaciones que no sean de transacción y que accedan a las mismas bases de datos o colecciones se bloquearán hasta que alcancen su límite de maxTimeMS.

Considera los siguientes escenarios:

Operación DDL que requiere un bloqueo de colección

Mientras una transacción en curso realiza diversas operaciones CRUD en la colección employees de la base de datos hr, un administrador emite la operación DDL db.collection.createIndex() en la colección employees. createIndex() requiere un bloqueo exclusivo en la colección.

Hasta que se complete la transacción en curso, la operación createIndex() debe esperar para obtener el bloqueo. Cualquier nueva transacción que afecte la colección employees y se inicie mientras la transacción createIndex() está pendiente, debe esperar a que createIndex() se complete.

La operación de DDL createIndex() pendiente no afecta a las transacciones en otras colecciones de la base de datos hr. Por ejemplo, una nueva transacción en la colección de contractors en la base de datos de hr puede comenzar y completarse con normalidad.

Operación DDL que requiere un bloqueo de base de datos

Si bien una transacción en curso realiza diversas operaciones CRUD en la colección employees de la base de datos hr, un administrador emite la operación DDL renameCollection para cambiar el nombre de la colección vendors.contractors a hr.contractors. renameCollection requiere un bloqueo de base de datos en la base de datos de destino (hr) cuando difiere de la base de datos de origen (vendors).

Hasta que la transacción en curso se complete, la operación de renameCollection debe esperar para obtener el bloqueo. Cualquier transacción nueva que afecte a la base de datos hr o cualquiera de sus colecciones y comience mientras renameCollection está pendiente debe esperar hasta que se complete renameCollection.

En cualquier escenario, si la operación de DDL permanece pendiente durante más de maxTransactionLockRequestTimeoutMillis, las transacciones pendientes que esperan detrás de esa operación se anulan. Es decir, el valor de maxTransactionLockRequestTimeoutMillis debe cubrir al menos el tiempo requerido para que la transacción en curso y la operación DDL pendiente se completen.

Si una transacción está en curso y una escritura fuera de la transacción modifica un documento que una operación de la transacción intenta modificar más adelante, la transacción se cancela por un conflicto de escritura.

Si hay una transacción en curso y se tomó un bloqueo para modificar un documento, cuando se intenta escribir algo fuera de la transacción para intentar modificar el mismo documento, la acción de escritura esperará a que finalice la transacción.

Las operaciones de lectura dentro de una transacción pueden devolver datos antiguos, lo que se conoce como una lectura obsoleta. No se garantiza que las operaciones de lectura dentro de una transacción vean las escrituras realizadas por otras transacciones confirmadas o escrituras no transaccionales. Por ejemplo, se deben considerar las siguientes posibilidades:

  1. Hay una transacción en curso.

  2. Una acción de guardado fuera de la transacción borra un documento.

  3. Una operación de lectura dentro de la transacción puede leer el documento que se borró, ya que la operación utiliza un snapshot anterior a la operación de guardado.

Para evitar lecturas obsoletas dentro de las transacciones de un solo documento, puedes utilizar el método db.collection.findOneAndUpdate(). En el siguiente ejemplo, mongosh demuestra cómo puedes usar db.collection.findOneAndUpdate() para tomar un bloqueo de escritura y garantizar que tus lecturas estén actualizadas:

1
db.getSiblingDB("hr").employees.insertOne(
{ _id: 1, status: "Active" }
)
2
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } )
3
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } )
employeesCollection = session.getDatabase("hr").employees
4
employeeDoc = employeesCollection.findOneAndUpdate(
{ _id: 1, status: "Active" },
{ $set: { lockId: ObjectId() } },
{ returnNewDocument: true }
)

Ten en cuenta que dentro de la transacción, la operación findOneAndUpdate establece un campo lockId nuevo. Puedes establecer el campo lockId en cualquier valor, siempre que modifique el documento. Al actualizar el documento, la transacción adquiere un bloqueo.

Si una operación externa a la transacción intenta modificar el documento antes de que confirmes la transacción, MongoDB devuelve un error de conflicto de escritura a la operación externa.

5
session.commitTransaction()

Después de que confirmes la transacción, MongoDB libera el bloqueo.

Nota

Si se produce un error en alguna operación en la transacción, esta se aborta y todos los cambios de datos realizados en la transacción se descartan sin llegar a ser visibles en la colección.

La migración por fragmentos adquiere bloqueos de colección exclusivos durante ciertas etapas.

Si una transacción en curso tiene un bloqueo sobre una colección y comienza una migración de fragmentos que involucra esa colección, estas etapas de migración deben esperar a que la transacción libere los bloqueos sobre la colección, lo que afecta el rendimiento de las migraciones de fragmentos.

Si una migración de fragmentos se entrelaza con una transacción (por ejemplo, si una transacción comienza mientras una migración de fragmentos ya está en curso y la migración se completa antes de que la transacción bloquee la colección), la transacción genera un error durante la confirmación y se aborta.

Según cómo se intercalan las dos operaciones, se incluyen algunos errores de muestra (los mensajes de error se han abreviado):

  • an error from cluster data placement change ... migration commit in progress for <namespace>

  • Cannot find shardId the chunk belonged to at cluster time ...

Durante la confirmación de una transacción, las operaciones de lectura externas pueden intentar leer los mismos documentos que modificará la transacción. Si la transacción guarda en múltiples particiones, entonces durante el intento de confirmación en las particiones:

  • Las lecturas externas que usan el nivel de consistencia de lectura "snapshot" o "linearizable" esperan hasta que todas las escrituras de una transacción sean visibles.

  • Las lecturas externas que forman parte de sesiones causalmente coherentes (aquellas que incluyen afterClusterTime) esperan hasta que todas las escrituras de una transacción sean visibles.

  • Las lecturas externas que usan otros niveles de consistencia de lectura no esperan a que todas las escrituras de una transacción sean visibles, sino que leen la versión de los documentos anterior a la transacción.

Volver

Operaciones