Comprender lecturas y escrituras a escala

Lea este documento para tomar decisiones informadas sobre la arquitectura de sus aplicaciones para lograr un alto rendimiento y confiabilidad. Este documento incluye temas avanzados de Cloud Firestore. Si recién estás comenzando con Cloud Firestore, consulta la guía de inicio rápido .

Cloud Firestore es una base de datos flexible y escalable para el desarrollo de dispositivos móviles, web y servidores de Firebase y Google Cloud. Es muy fácil comenzar con Cloud Firestore y escribir aplicaciones ricas y potentes.

Para asegurarse de que sus aplicaciones sigan funcionando bien a medida que aumentan el tamaño de su base de datos y el tráfico, es útil comprender la mecánica de lecturas y escrituras en el backend de Cloud Firestore. También debe comprender la interacción de sus lecturas y escrituras con la capa de almacenamiento y las limitaciones subyacentes que pueden afectar el rendimiento.

Consulte las siguientes secciones para conocer las mejores prácticas antes de diseñar su aplicación.

Comprender los componentes de alto nivel.

El siguiente diagrama muestra los componentes de alto nivel involucrados en una solicitud de API de Cloud Firestore.

Componentes de alto nivel

SDK de Cloud Firestore y bibliotecas cliente

Cloud Firestore admite SDK y bibliotecas cliente para diferentes plataformas. Si bien una aplicación puede realizar llamadas HTTP y RPC directas a la API de Cloud Firestore, las bibliotecas cliente proporcionan una capa de abstracción para simplificar el uso de la API e implementar las mejores prácticas. También pueden proporcionar funciones adicionales como acceso sin conexión, cachés, etc.

Interfaz de Google (GFE)

Este es un servicio de infraestructura común a todos los servicios en la nube de Google. El GFE acepta las solicitudes entrantes y las reenvía al servicio de Google correspondiente (en este contexto, el servicio Firestore). También proporciona otras funcionalidades importantes, incluida la protección contra ataques de denegación de servicio.

Servicio Cloud Firestore

El servicio Cloud Firestore realiza comprobaciones de la solicitud de API, que incluyen autenticación, autorización, comprobaciones de cuotas y reglas de seguridad, y también gestiona las transacciones. Este servicio Cloud Firestore incluye un cliente de almacenamiento que interactúa con la capa de almacenamiento para las lecturas y escrituras de datos.

Capa de almacenamiento de Cloud Firestore

La capa de almacenamiento de Cloud Firestore es responsable de almacenar tanto los datos como los metadatos, y las funciones de base de datos asociadas proporcionadas por Cloud Firestore. Las siguientes secciones describen cómo se organizan los datos en la capa de almacenamiento de Cloud Firestore y cómo se escala el sistema. Aprender cómo se organizan los datos puede ayudarte a diseñar un modelo de datos escalable y comprender mejor las mejores prácticas en Cloud Firestore.

Rangos clave y divisiones

Cloud Firestore es una base de datos NoSQL orientada a documentos. Los datos se almacenan en documentos , que están organizados en jerarquías de colecciones . La jerarquía de la colección y el ID del documento se traducen a una única clave para cada documento. Los documentos se almacenan lógicamente y se ordenan lexicográficamente mediante esta única clave. Usamos el término rango de claves para referirnos a un rango de claves lexicográficamente contiguas.

Una base de datos típica de Cloud Firestore es demasiado grande para caber en una sola máquina física. También hay escenarios en los que la carga de trabajo de los datos es demasiado pesada para que la maneje una sola máquina. Para manejar grandes cargas de trabajo, Cloud Firestore divide los datos en partes separadas que se pueden almacenar y servir desde varias máquinas o servidores de almacenamiento . Estas particiones se realizan en las tablas de la base de datos en bloques de rangos de claves llamados divisiones.

Replicación sincrónica

Es importante tener en cuenta que la base de datos siempre se replica de forma automática y sincrónica. Las divisiones de datos tienen réplicas en diferentes zonas para mantenerlas disponibles incluso cuando una zona se vuelve inaccesible. El algoritmo de Paxos gestiona la replicación coherente de las diferentes copias de la división para lograr consenso. Se elige una réplica de cada división para actuar como líder de Paxos, que es responsable de manejar las escrituras en esa división. La replicación sincrónica le brinda la posibilidad de poder leer siempre la última versión de los datos de Cloud Firestore.

El resultado general de esto es un sistema escalable y de alta disponibilidad que proporciona latencias bajas tanto para lectura como para escritura, independientemente de cargas de trabajo pesadas y a gran escala.

Diseño de datos

Cloud Firestore es una base de datos de documentos sin esquema. Sin embargo, internamente presenta los datos principalmente en dos tablas estilo base de datos relacional en su capa de almacenamiento de la siguiente manera:

  • Tabla de documentos : Los documentos se almacenan en esta tabla.
  • Tabla de índices : en esta tabla se almacenan las entradas de índice que permiten obtener resultados de manera eficiente y ordenados por valor de índice.

El siguiente diagrama muestra cómo se verían las tablas de una base de datos de Cloud Firestore con las divisiones. Las divisiones se replican en tres zonas diferentes y cada división tiene un líder de Paxos asignado.

Diseño de datos

Región única versus varias regiones

Cuando creas una base de datos, debes seleccionar una región o multirregión .

Una ubicación regional única es una ubicación geográfica específica, como us-west1 . Las divisiones de datos de una base de datos de Cloud Firestore tienen réplicas en diferentes zonas dentro de la región seleccionada, como se explicó anteriormente.

Una ubicación de varias regiones consta de un conjunto definido de regiones donde se almacenan réplicas de la base de datos. En una implementación de Cloud Firestore en varias regiones, dos de las regiones tienen réplicas completas de todos los datos de la base de datos. Una tercera región tiene una réplica testigo que no mantiene un conjunto completo de datos, pero participa en la replicación. Al replicar los datos entre múltiples regiones, los datos están disponibles para escribirse y leerse incluso con la pérdida de una región completa.

Para obtener más información sobre las ubicaciones de una región, consulte Ubicaciones de Cloud Firestore .

Una sola región versus varias regiones

Comprender la vida de una escritura en Cloud Firestore

Un cliente de Cloud Firestore puede escribir datos creando, actualizando o eliminando un solo documento. Una escritura en un solo documento requiere actualizar atómicamente tanto el documento como sus entradas de índice asociadas en la capa de almacenamiento. Cloud Firestore también admite operaciones atómicas que consisten en múltiples lecturas y/o escrituras en uno o más documentos.

Para todo tipo de escrituras, Cloud Firestore proporciona las propiedades ACID (atomicidad, coherencia, aislamiento y durabilidad) de las bases de datos relacionales. Cloud Firestore también proporciona serialización , lo que significa que todas las transacciones aparecen como si se hubieran ejecutado en un orden en serie.

Pasos de alto nivel en una transacción de escritura

Cuando el cliente de Cloud Firestore emite una escritura o confirma una transacción, utilizando cualquiera de los métodos mencionados anteriormente, internamente esto se ejecuta como una transacción de lectura y escritura de la base de datos en la capa de almacenamiento. La transacción permite a Cloud Firestore proporcionar las propiedades ACID mencionadas anteriormente.

Como primer paso de una transacción, Cloud Firestore lee el documento existente y determina las mutaciones que se realizarán en los datos de la tabla Documentos.

Esto también incluye realizar las actualizaciones necesarias a la tabla de Índices de la siguiente manera:

  • Los campos que se agregan a los documentos necesitan las inserciones correspondientes en la tabla Índices.
  • Los campos que se eliminan de los documentos deben eliminarse correspondientemente en la tabla Índices.
  • Los campos que se están modificando en los documentos necesitan tanto eliminaciones (para valores antiguos) como inserciones (para valores nuevos) en la tabla Índices.

Para calcular las mutaciones mencionadas anteriormente, Cloud Firestore lee la configuración de indexación del proyecto. La configuración de indexación almacena información sobre los índices de un proyecto. Cloud Firestore utiliza dos tipos de índices: de campo único y compuestos. Para obtener una comprensión detallada de los índices creados en Cloud Firestore, consulte Tipos de índice en Cloud Firestore .

Una vez calculadas las mutaciones, Cloud Firestore las recopila dentro de una transacción y luego la confirma.

Comprender una transacción de escritura en la capa de almacenamiento

Como se mencionó anteriormente, una escritura en Cloud Firestore implica una transacción de lectura y escritura en la capa de almacenamiento. Dependiendo del diseño de los datos, una escritura puede implicar una o más divisiones, como se ve en el diseño de los datos .

En el siguiente diagrama, la base de datos de Cloud Firestore tiene ocho divisiones (marcadas del 1 al 8) alojadas en tres servidores de almacenamiento diferentes en una sola zona, y cada división se replica en 3 (o más) zonas diferentes. Cada división tiene un líder de Paxos, que puede estar en una zona diferente para diferentes divisiones.

División de la base de datos de Cloud Firestore

Considere una base de datos de Cloud Firestore que tenga la colección Restaurants de la siguiente manera:

Colección de restaurante

El cliente de Cloud Firestore solicita el siguiente cambio en un documento de la colección Restaurant actualizando el valor del campo priceCategory .

Cambiar a un documento en colección

Los siguientes pasos de alto nivel describen lo que sucede como parte de la escritura:

  1. Cree una transacción de lectura-escritura.
  2. Lea el documento restaurant1 en la colección Restaurants de la tabla Documentos de la capa de almacenamiento.
  3. Lea los índices del documento en la tabla Índices .
  4. Calcule las mutaciones que se realizarán en los datos. En este caso, existen cinco mutaciones:
    • M1: actualice la fila del restaurant1 en la tabla Documentos para reflejar el cambio en el valor del campo priceCategory .
    • M2 y M3: elimine las filas del valor anterior de priceCategory en la tabla Índices para índices descendentes y ascendentes.
    • M4 y M5: inserte las filas para el nuevo valor de priceCategory en la tabla Índices para índices descendentes y ascendentes.
  5. Cometer estas mutaciones.

El cliente de almacenamiento en el servicio Cloud Firestore busca las divisiones propietarias de las claves de las filas que se van a cambiar. Consideremos un caso en el que Split 3 sirve a M1 y Split 6 sirve a M2-M5. Hay una transacción distribuida que involucra a todas estas divisiones como participantes . Las divisiones de participantes también pueden incluir cualquier otra división de la cual se leyeron datos anteriormente como parte de la transacción de lectura y escritura.

Los siguientes pasos describen lo que sucede como parte de la confirmación:

  1. El cliente de almacenamiento emite una confirmación. La confirmación contiene las mutaciones M1-M5.
  2. Los splits 3 y 6 son los participantes en esta transacción. Uno de los participantes es elegido como coordinador , como en Split 3. El trabajo del coordinador es asegurarse de que la transacción se confirme o aborte atómicamente entre todos los participantes.
    • Las réplicas líderes de estas divisiones son responsables del trabajo realizado por los participantes y coordinadores.
  3. Cada participante y coordinador ejecuta un algoritmo Paxos con sus respectivas réplicas.
    • El líder ejecuta un algoritmo Paxos con las réplicas. El quórum se logra si la mayoría de las réplicas responden con un ok to commit la respuesta al líder.
    • Luego, cada participante notifica al coordinador cuando está preparado (primera fase del compromiso de dos fases). Si algún participante no puede realizar la transacción, toda la transacción aborts .
  4. Una vez que el coordinador sabe que todos los participantes, incluido él mismo, están preparados, comunica el resultado de la transacción accept a todos los participantes (segunda fase del compromiso de dos fases). En esta fase, cada participante registra la decisión de confirmación en un almacenamiento estable y se confirma la transacción.
  5. El coordinador responde al cliente de almacenamiento en Cloud Firestore que la transacción se ha confirmado. Paralelamente, el coordinador y todos los participantes aplican las mutaciones a los datos.

Confirmar ciclo de vida

Cuando la base de datos de Cloud Firestore es pequeña, puede suceder que un único split posea todas las claves en las mutaciones M1-M5. En tal caso, solo hay un participante en la transacción y no se requiere la confirmación de dos fases mencionada anteriormente, lo que hace que las escrituras sean más rápidas.

Escribe en varias regiones

En una implementación multirregional, la distribución de réplicas entre regiones aumenta la disponibilidad, pero conlleva un costo de rendimiento. La comunicación entre réplicas en diferentes regiones requiere tiempos de ida y vuelta más largos. Por lo tanto, la latencia básica para las operaciones de Cloud Firestore es ligeramente mayor en comparación con las implementaciones de una sola región.

Configuramos las réplicas de manera que el liderazgo en caso de escisión siempre permanezca en la región primaria. La región principal es aquella desde la cual el tráfico ingresa al servidor de Cloud Firestore. Esta decisión de liderazgo reduce el retraso de ida y vuelta en la comunicación entre el cliente de almacenamiento en Cloud Firestore y el líder de réplica (o coordinador para transacciones multisplit).

Cada escritura en Cloud Firestore también implica cierta interacción con el motor en tiempo real de Cloud Firestore. Para obtener más información sobre consultas en tiempo real, consulte Comprender las consultas en tiempo real a escala .

Comprender la vida de una lectura en Cloud Firestore

Esta sección profundiza en las lecturas independientes y no en tiempo real en Cloud Firestore. Internamente, el servidor Cloud Firestore maneja la mayoría de estas consultas en dos etapas principales:

  1. Un escaneo de rango único sobre la tabla de índices
  2. Búsquedas de puntos en la tabla Documentos según el resultado del escaneo anterior
Es posible que haya determinadas consultas que requieran menos o más procesamiento (por ejemplo, consultas IN) en Cloud Firestore.

Las lecturas de datos de la capa de almacenamiento se realizan internamente mediante una transacción de base de datos para garantizar lecturas consistentes. Sin embargo, a diferencia de las transacciones utilizadas para escrituras, estas transacciones no requieren bloqueos. En cambio, funcionan eligiendo una marca de tiempo y luego ejecutando todas las lecturas en esa marca de tiempo. Como no adquieren bloqueos, no bloquean transacciones simultáneas de lectura y escritura. Para ejecutar esta transacción, el cliente de almacenamiento en Cloud Firestore especifica un límite de marca de tiempo, que le indica a la capa de almacenamiento cómo elegir una marca de tiempo de lectura. El tipo de marca de tiempo elegida por el cliente de almacenamiento en Cloud Firestore está determinado por las opciones de lectura para la solicitud de lectura.

Comprender una transacción de lectura en la capa de almacenamiento

Esta sección describe los tipos de lecturas y cómo se procesan en la capa de almacenamiento en Cloud Firestore.

lecturas fuertes

De forma predeterminada, las lecturas de Cloud Firestore son muy consistentes . Esta fuerte coherencia significa que una lectura de Cloud Firestore devuelve la última versión de los datos que refleja todas las escrituras que se han confirmado hasta el inicio de la lectura.

Lectura dividida única

El cliente de almacenamiento en Cloud Firestore busca las divisiones que poseen las claves de las filas que se van a leer. Supongamos que necesita realizar una lectura de la división 3 de la sección anterior. El cliente envía la solicitud de lectura a la réplica más cercana para reducir la latencia de ida y vuelta.

En este punto, pueden ocurrir los siguientes casos dependiendo de la réplica elegida:

  • La solicitud de lectura va a una réplica del líder (Zona A).
    • Como el líder está siempre actualizado, la lectura puede continuar directamente.
  • La solicitud de lectura va a una réplica que no es líder (como la Zona B)
    • La división 3 puede saber por su estado interno que tiene suficiente información para realizar la lectura y la división lo hace.
    • Split 3 no está seguro de haber visto los datos más recientes. Envía un mensaje al líder para solicitar la marca de tiempo de la última transacción que necesita aplicar para realizar la lectura. Una vez que se aplica esa transacción, la lectura puede continuar.

Luego, Cloud Firestore devuelve la respuesta a su cliente.

Lectura multidividida

En la situación en la que las lecturas deben realizarse desde múltiples divisiones, ocurre el mismo mecanismo en todas las divisiones. Una vez que se han devuelto los datos de todas las divisiones, el cliente de almacenamiento en Cloud Firestore combina los resultados. Luego, Cloud Firestore responde a su cliente con estos datos.

Lecturas obsoletas

Las lecturas seguras son el modo predeterminado en Cloud Firestore. Sin embargo, esto tiene el costo de una latencia potencialmente mayor debido a la comunicación que puede ser necesaria con el líder. A menudo, su aplicación Cloud Firestore no necesita leer la última versión de los datos y la funcionalidad funciona bien con datos que pueden estar obsoletos durante unos segundos.

En tal caso, el cliente puede optar por recibir lecturas obsoletas utilizando las opciones de lectura read_time . En este caso, las lecturas se realizan cuando los datos estaban en read_time y es muy probable que la réplica más cercana ya haya verificado que tiene datos en el read_time especificado. Para un rendimiento notablemente mejor, 15 segundos es un valor de estancamiento razonable. Incluso para lecturas obsoletas, las filas obtenidas son coherentes entre sí.

Evite los puntos de acceso

Las divisiones en Cloud Firestore se dividen automáticamente en partes más pequeñas para distribuir el trabajo de atender el tráfico a más servidores de almacenamiento cuando sea necesario o cuando se expanda el espacio clave. Las divisiones creadas para manejar el exceso de tráfico se conservan durante aproximadamente 24 horas, incluso si el tráfico desaparece. Entonces, si hay picos de tráfico recurrentes, las divisiones se mantienen y se introducen más divisiones cuando sea necesario. Estos mecanismos ayudan a que las bases de datos de Cloud Firestore se escalen automáticamente cuando la carga de tráfico o el tamaño de la base de datos aumentan. Sin embargo, existen algunas limitaciones que se deben tener en cuenta, como se explica a continuación.

Dividir el almacenamiento y la carga lleva tiempo, y aumentar el tráfico demasiado rápido puede provocar errores de latencia alta o de superación de plazos, comúnmente conocidos como puntos de acceso , mientras el servicio se ajusta. La mejor práctica es distribuir las operaciones en todo el rango de claves y, al mismo tiempo, aumentar el tráfico en una colección en una base de datos con 500 operaciones por segundo. Después de este aumento gradual, aumente el tráfico hasta en un 50% cada cinco minutos. Este proceso se denomina regla 500/50/5 y posiciona la base de datos para escalar de manera óptima para satisfacer su carga de trabajo.

Aunque las divisiones se crean automáticamente al aumentar la carga, Cloud Firestore puede dividir un rango de claves solo hasta que entregue un solo documento utilizando un conjunto dedicado de servidores de almacenamiento replicados. Como resultado, volúmenes altos y sostenidos de operaciones simultáneas en un solo documento pueden generar un punto de acceso en ese documento. Si encuentra latencias altas y sostenidas en un solo documento, debería considerar modificar su modelo de datos para dividir o replicar los datos en varios documentos.

Los errores de contención ocurren cuando varias operaciones intentan leer y/o escribir el mismo documento simultáneamente.

Otro caso especial de hotspotting ocurre cuando se utiliza una clave que aumenta o disminuye secuencialmente como ID del documento en Cloud Firestore y hay una cantidad considerablemente alta de operaciones por segundo. Crear más divisiones no ayuda aquí, ya que el aumento de tráfico simplemente se traslada a la división recién creada. Dado que Cloud Firestore indexa automáticamente todos los campos del documento de forma predeterminada, dichos puntos de acceso móviles también se pueden crear en el espacio de índice para un campo del documento que contiene un valor que aumenta o disminuye secuencialmente, como una marca de tiempo.

Tenga en cuenta que, al seguir las prácticas descritas anteriormente, Firestore puede escalar para atender cargas de trabajo arbitrariamente grandes sin que usted tenga que ajustar ninguna configuración.

Solución de problemas

Firestore proporciona Key Visualizer como una herramienta de diagnóstico diseñada específicamente para analizar patrones de uso y solucionar problemas de puntos de acceso.

Que sigue