Contención de datos en transacciones

En esta página se describe la contención de datos transaccionales, la serializabilidad y el aislamiento. Para ver ejemplos de código de transacciones, consulta Transacciones y escrituras por lotes.

Transacciones y contención de datos

Para que una transacción se complete correctamente, los documentos obtenidos por sus operaciones de lectura no deben modificarse mediante operaciones fuera de la transacción. Si otra operación intenta cambiar uno de esos documentos, la operación entra en un estado de contención de datos con la transacción.

Contención de datos
Cuando dos o más operaciones compiten por controlar el mismo documento. Por ejemplo, una transacción puede requerir que un documento siga siendo coherente mientras una operación simultánea intenta actualizar los valores de los campos de ese documento.

Firestore resuelve la contención de datos retrasando o rechazando una de las operaciones. Las bibliotecas de cliente de Firestore vuelven a intentar automáticamente las transacciones que fallan debido a la contención de datos. Después de un número finito de reintentos, la operación de transacción falla y devuelve un mensaje de error:

ABORTED: Too much contention on these documents. Please try again.

A la hora de decidir qué operación debe fallar o retrasarse, el comportamiento depende del tipo de biblioteca de cliente.

Firestore se puede configurar con un modo de simultaneidad: PESSIMISTIC o OPTIMISTIC. El valor predeterminado de la edición estándar es PESSIMISTIC, mientras que el de la edición Enterprise es OPTIMISTIC. (PESSIMISTIC) es la opción recomendada. Los SDKs para móviles y web se comportan de forma independiente a este ajuste, ya que siempre emulan la simultaneidad optimista.

  • Los SDKs para móviles y web usan controles de simultaneidad optimista.

  • Las bibliotecas de cliente del servidor usan controles de simultaneidad pesimistas.

Contención de datos en los SDKs para móviles y web

Los SDKs web y para móviles emulan transacciones de simultaneidad optimista mediante precondiciones de escritura en versiones de documentos. Esta emulación se produce independientemente del ajuste del modo de simultaneidad de la base de datos. Los SDKs web y para móviles no usan la función de transacciones integradas, por lo que, aunque el modo de simultaneidad de la base de datos esté configurado como PESSIMISTIC, los clientes móviles seguirán comportándose de forma optimista.

Controles de simultaneidad optimista
Se basa en la suposición de que no es probable que se produzca una contención de datos o de que no sea eficiente mantener los bloqueos de la base de datos. Las transacciones optimistas no usan bloqueos de bases de datos para impedir que otras operaciones cambien los datos.

Los SDKs para móviles y web usan controles de simultaneidad optimistas, ya que pueden funcionar en entornos con una latencia alta y una conexión de red poco fiable. Bloquear documentos en un entorno de alta latencia provocaría demasiados errores de contención de datos.

En los SDKs para móviles y web, una transacción registra todos los documentos que lees en la transacción. La transacción completa sus operaciones de escritura solo si ninguno de esos documentos ha cambiado durante la ejecución de la transacción. Si se ha modificado algún documento, el controlador de transacciones vuelve a intentar la transacción. Si la transacción no obtiene un resultado limpio después de varios reintentos, se produce un error debido a la contención de datos.

Contención de datos en las bibliotecas de cliente del servidor

Las bibliotecas de cliente de servidor (C#, Go, Java, Node.js, PHP, Python y Ruby) usan la función de transacciones integradas, que implementa de forma predeterminada controles de simultaneidad pesimistas. Estas transacciones respetan el ajuste del modo de simultaneidad a nivel de base de datos (normalmente, PESSIMISTIC) y usan bloqueos de documentos para evitar escrituras conflictivas.

Controles de simultaneidad pesimistas
Se basa en la suposición de que es probable que haya contención de datos. Las transacciones pesimistas usan bloqueos de bases de datos para evitar que otras operaciones modifiquen los datos.

Las bibliotecas de cliente del servidor usan controles de simultaneidad pesimistas, ya que asumen una latencia baja y una conexión fiable a la base de datos.

En las bibliotecas de cliente del servidor, las transacciones bloquean los documentos que leen. El bloqueo de una transacción en un documento impide que otras transacciones, escrituras por lotes y escrituras no transaccionales cambien ese documento. Una transacción libera sus bloqueos de documentos en el momento de la confirmación. También libera sus bloqueos si se agota el tiempo de espera o falla por cualquier motivo.

Cuando una transacción bloquea un documento, otras operaciones de escritura deben esperar a que la transacción libere el bloqueo. Las transacciones adquieren sus bloqueos en orden cronológico.

Aislamiento serializable

La contención de datos entre transacciones está estrechamente relacionada con los niveles de aislamiento de la base de datos. El nivel de aislamiento de una base de datos describe cómo gestiona el sistema los conflictos entre operaciones simultáneas. El conflicto se debe a los siguientes requisitos de la base de datos:

  • Las transacciones requieren datos precisos y coherentes.
  • Para usar los recursos de forma eficiente, las bases de datos ejecutan operaciones simultáneamente.

En los sistemas con un nivel de aislamiento bajo, una operación de lectura dentro de una transacción puede leer datos inexactos de cambios no confirmados en una operación simultánea.

Aislamiento serializable: define el nivel de aislamiento más alto. El aislamiento serializable significa que:

  • Puedes suponer que la base de datos ejecuta las transacciones en serie.
  • Las transacciones no se ven afectadas por los cambios no confirmados en operaciones simultáneas.

Esta garantía debe mantenerse incluso mientras la base de datos ejecuta varias transacciones en paralelo. La base de datos debe implementar controles de simultaneidad para resolver los conflictos que puedan incumplir esta garantía.

Firestore garantiza el aislamiento serializable de las transacciones. Las transacciones de Firestore se serializan y se aíslan por hora de confirmación.

Aislamiento serializable por hora de confirmación

Firestore asigna a cada transacción una hora de confirmación que representa un momento concreto. Cuando Firestore confirma los cambios de una transacción en la base de datos, puedes suponer que todas las lecturas y escrituras de la transacción se producen exactamente en el momento de la confirmación.

La ejecución real de una transacción requiere un periodo de tiempo. La ejecución de una transacción comienza antes de la hora de confirmación y la ejecución de varias operaciones puede superponerse. Firestore mantiene el aislamiento serializable y garantiza lo siguiente:

  • Firestore confirma las transacciones en orden según la hora de confirmación.
  • Firestore aísla las transacciones de las operaciones simultáneas con una hora de confirmación posterior.

En el caso de que haya una contención de datos entre operaciones simultáneas, Firestore usa controles de simultaneidad optimistas y pesimistas para resolver la contención.

Aislamiento en una transacción

El aislamiento de las transacciones también se aplica a las operaciones de escritura dentro de una transacción. Las consultas y lecturas dentro de una transacción no ven los resultados de las escrituras anteriores dentro de esa transacción. Aunque modifiques o elimines un documento en una transacción, todas las lecturas de documentos de esa transacción devuelven la versión del documento en el momento de la confirmación, antes de las operaciones de escritura de la transacción. Las operaciones de lectura no devuelven nada si el documento no existía en ese momento.

Problemas con la contención de datos

Para obtener más información sobre la contención de datos y cómo resolverla, consulta la página de solución de problemas.