Información sobre las consultas en tiempo real a gran escala
Lee este documento si quieres obtener orientación para escalar tu app sin servidores para abarcar incluso más que miles de operaciones por segundo o cientos de miles de usuarios simultáneos. En este documento, se incluyen temas avanzados para ayudarte a comprender el sistema en profundidad. Si recién comienzas a usar Firestore, consulta la guía de inicio rápido.
Firestore y los SDK para dispositivos móviles y la Web de Firebase proporcionan un modelo potente para desarrollar apps sin servidores en las que el código del cliente accede directamente a la base de datos. Los SDK permiten a los clientes detectar las actualizaciones de los datos en tiempo real. Puedes usar actualizaciones en tiempo real para compilar apps responsivas que no requieren infraestructura de servidores. Si bien es muy fácil poner en marcha algo, es útil comprender las restricciones de los sistemas que conforman Firestore para que tu app sin servidores escale y funcione bien cuando aumente el tráfico.
Consulta las siguientes secciones para obtener consejos sobre cómo escalar tu app.
Elige una ubicación para la base de datos cercana a tus usuarios
En el siguiente diagrama, se muestra la arquitectura de una app en tiempo real:
Cuando una app que se ejecuta en el dispositivo de un usuario (dispositivo móvil o web), establece una
conexión con Firestore, la conexión se enruta a un
servidor de frontend de Firestore en la misma
región en la que se encuentra tu base de datos. Por ejemplo, si tu base de datos está en us-east1
, la conexión también va a un frontend de Firestore en us-east1
. Estas conexiones son
de larga duración y permanecen abiertas hasta que la app las cierra de manera explícita. El
frontend lee datos de los sistemas de almacenamiento subyacentes de Firestore.
La distancia entre la ubicación física de un usuario y la ubicación de la base de datos de Firestore afecta la latencia que experimenta el usuario. Por ejemplo, a un usuario de India cuya app se comunica con una base de datos en una región de Google Cloud de Norteamérica puede resultarle más lenta la experiencia, y la app menos ágil, que si la base de datos estuviera en un lugar más cercano, como India o alguna otra parte de Asia.
Diseño para la disponibilidad
Los siguientes temas mejoran o afectan la confiabilidad de tu app:
Habilita el modo sin conexión
Los SDK de Firebase proporcionan persistencia de datos sin conexión. Si la app en el dispositivo del usuario no puede conectarse a Firestore, seguirá funcionando con datos almacenados en caché local. Esto garantiza el acceso a los datos, incluso cuando los usuarios experimentan conexiones a Internet irregulares o pierden por completo el acceso por varias horas o días. Para conocer más detalles sobre el modo sin conexión, consulta Habilita datos sin conexión.
Información sobre los reintentos automáticos
Los SDK de Firebase se encargan de reintentar las operaciones y restablecer las conexiones dañadas. Esto ayuda a solucionar errores transitorios que se producen cuando se reinician los servidores o cuando hay problemas de red entre el cliente y la base de datos.
Elige entre ubicaciones regionales y multirregionales
Existen varias compensaciones cuando se elige entre ubicaciones regionales y multirregionales. La principal diferencia es la forma en que se replican los datos. Esto genera las garantías de disponibilidad de tu app. Una instancia multirregional proporciona una mayor confiabilidad de entrega y aumenta la durabilidad de tus datos, pero también aumenta el costo.
Comprende el sistema de consultas en tiempo real
Las consultas en tiempo real, también llamadas objetos de escucha de instantáneas, permiten que la app detecte los cambios en la base de datos y reciba notificaciones de latencia baja apenas cambien los datos. Una app puede obtener el mismo resultado si sondea periódicamente la base de datos en busca de actualizaciones, pero suele ser más lenta, más costosa y requiere de más código. Para conocer ejemplos sobre cómo configurar y usar las consultas en tiempo real, lee el artículo Obtén actualizaciones en tiempo real. En las siguientes secciones, se explica en detalle cómo funcionan los objetos de escucha de instantáneas y se describen algunas de las prácticas recomendadas para escalar consultas en tiempo real a la vez que se mantiene el rendimiento.
Imagina que dos usuarios se conectan a Firestore a través de una app de mensajería compilada con uno de los SDK para dispositivos móviles.
El cliente A escribe en la base de datos para agregar y actualizar documentos en una colección
llamada chatroom
:
collection chatroom:
document message1:
from: 'Sparky'
message: 'Welcome to Firestore!'
document message2:
from: 'Santa'
message: 'Presents are coming'
El cliente B detecta actualizaciones en la misma colección mediante un objeto de escucha de instantáneas. El cliente B recibe una notificación inmediata cada vez que alguien crea un mensaje nuevo. En el siguiente diagrama, se muestra la arquitectura de un objeto de escucha de instantáneas:
La siguiente secuencia de eventos ocurre cuando el cliente B conecta un objeto de escucha de instantáneas a la base de datos:
- El cliente B abre una conexión a Firestore y registra un
objeto de escucha mediante una llamada a
onSnapshot(collection("chatroom"))
a través del SDK de Firebase. Este objeto de escucha puede permanecer activo durante horas. - El frontend de Firestore consulta el sistema de almacenamiento subyacente para iniciar el conjunto de datos. Carga todo el conjunto de resultados de documentos coincidentes. Nos referimos a esto como una consulta de sondeo. Luego, el sistema evalúa las reglas de seguridad de Firebase de la base de datos para verificar que el usuario pueda acceder a estos datos. Si el usuario tiene autorización, la base de datos le muestra los datos.
- Luego, la consulta del cliente B pasa al modo de escucha. El objeto de escucha se registra con un controlador de suscripción y espera a que se actualicen los datos.
- El cliente A ahora envía una operación de escritura para modificar un documento.
- La base de datos confirma el cambio del documento en su sistema de almacenamiento.
- De manera transaccional, el sistema confirma la misma actualización en un registro de cambios interno. Este registro establece un orden estricto de los cambios a medida que ocurren.
- Al mismo tiempo, realiza un fan-out de los datos actualizados en un grupo de controladores de suscripción.
- Se ejecuta un comparador de consultas inversas para ver si el documento actualizado coincide con algún objeto de escucha de instantáneas registrado actualmente. En este ejemplo, el documento coincide con el objeto de escucha de instantáneas del cliente B. Como su nombre lo indica, puedes considerar al comparador de consultas inversas como una consulta normal de base de datos, pero que se realiza de forma inversa. En lugar de hacer una búsqueda en los documentos para encontrar aquellos que coinciden con una consulta, busca de manera eficiente en las consultas con el fin de encontrar aquellas que coincidan con un documento entrante. Cuando se encuentra una coincidencia, el sistema reenvía el documento en cuestión a los objetos de escucha de instantáneas. Luego, el sistema evalúa las reglas de seguridad de Firebase de la base de datos para garantizar que solo los usuarios autorizados reciban los datos.
- El sistema reenvía la actualización del documento al SDK en el dispositivo del cliente, y
se activa la devolución de llamada
onSnapshot
. Si la persistencia local está habilitada, el SDK también aplica la actualización a la caché local.
Una parte clave de la escalabilidad de Firestore depende del fan-out del registro de cambios en los controladores de suscripción y los servidores de frontend. El fan-out permite que un solo cambio de datos se propague de manera eficiente para entregar millones de consultas en tiempo real y brindar el servicio a millones de usuarios conectados. Cuando se ejecutan muchas réplicas de todos estos componentes en varias zonas (o varias regiones en el caso de una implementación multirregional), Firestore logra alta disponibilidad y escalabilidad.
Vale la pena señalar que todas las operaciones de lectura emitidas desde los SDK para dispositivos móviles y la Web siguen el modelo anterior. Realizan una consulta de sondeo seguida del modo de escucha para mantener las garantías de coherencia. Esto también se aplica a los objetos de escucha en tiempo real, a las llamadas para recuperar un documento y a las consultas únicas. Puedes considerar a las recuperaciones de documentos individuales y las consultas únicas como objetos de escucha de instantáneas de corta duración que tienen restricciones similares en cuanto al rendimiento.
Aplica las prácticas recomendadas para escalar consultas en tiempo real
Aplica las siguientes prácticas recomendadas para diseñar consultas en tiempo real escalables.
Comprende el tráfico alto de escritura en el sistema
Esta sección te ayudará a comprender cómo responde el sistema a una mayor cantidad de solicitudes de escritura.
Los registros de cambios de Firestore que generan las consultas en tiempo real escalan de forma horizontal y automática a medida que aumenta el tráfico de escritura. A medida que la tasa de escritura de una base de datos aumenta más de lo que puede manejar un solo servidor, el registro de cambios se divide en varios servidores, y el procesamiento de consultas comienza a consumir datos de múltiples controladores de suscripción en lugar de uno. Desde la perspectiva del cliente y del SDK, todo esto es transparente y no se requiere ninguna acción de la app cuando se realizan las divisiones. En el siguiente diagrama, se muestra cómo se escalan las consultas en tiempo real:
El ajuste de escala automático te permite aumentar el tráfico de escritura sin límites, pero a medida que el tráfico aumente, el sistema puede tardar un poco en responder. Sigue las recomendaciones de la regla de 5/5/5 para evitar crear un hotspot de escritura. Key Visualizer es una herramienta útil para analizar hotspots de escritura.
Muchas apps tienen un crecimiento orgánico predecible al que Firestore puede adaptarse sin precauciones. Sin embargo, las cargas de trabajo por lotes, como la importación de un conjunto de datos grande, pueden aumentar las operaciones de escritura con demasiada rapidez. Cuando diseñes la app, ten en cuenta de dónde proviene el tráfico de escritura.
Comprende cómo interactúan las operaciones de escritura y lectura
Puedes considerar al sistema de consultas en tiempo real como una canalización que conecta las operaciones de escritura con los lectores. Cada vez que se crea, actualiza o borra un documento, el cambio se propaga desde el sistema de almacenamiento a los objetos de escucha registrados actualmente. La estructura del registro de cambios de Firestore garantiza una coherencia sólida, lo que significa que tu app nunca recibe notificaciones de actualizaciones desordenadas con respecto al momento en que la base de datos confirmó los cambios en los datos. Esto simplifica el desarrollo de apps, ya que quita los casos extremos relacionados con la coherencia de los datos.
Esta canalización conectada significa que una operación de escritura que causa hotspots o contención de bloqueo puede afectar negativamente las operaciones de lectura. Cuando las operaciones de escritura fallan o experimentan una limitación, es posible que una operación de lectura se detenga a la espera de datos coherentes provenientes del registro de cambios. Si esto sucede en tu app, es posible que veas operaciones de escritura lentas y tiempos de respuesta lentos correlacionados para las consultas. Evitar los hotspots es la clave para prevenir este problema.
Limita el tamaño de las operaciones de escritura y los documentos
Cuando compilas apps con objetos de escucha de instantáneas, por lo general, es ideal que los usuarios se enteren de los cambios en los datos con rapidez. Para lograrlo, intenta limitar el tamaño de los elementos. El sistema puede enviar documentos pequeños con decenas de campos por el sistema con mucha rapidez. Los documentos de mayor tamaño con cientos de campos y datos grandes tardan más en procesarse.
Del mismo modo, prioriza las operaciones de escritura y confirmación rápidas y breves para mantener baja la latencia. Los lotes grandes pueden brindarte una mayor capacidad de procesamiento desde la perspectiva del escritor, pero, en realidad, pueden aumentar el tiempo de notificación para los objetos de escucha de instantáneas. Esto suele ser contraintuitivo en comparación con el uso de otros sistemas de bases de datos en los que podrías usar el procesamiento por lotes para mejorar el rendimiento.
Usa objetos de escucha eficaces
A medida que aumentan las tasas de escritura de tu base de datos, Firestore divide el procesamiento de datos en muchos servidores. El algoritmo de fragmentación de Firestore intenta ubicar los datos de la misma colección o grupo de colecciones en el mismo servidor de registros de cambios. El sistema intenta maximizar la capacidad de procesamiento de escritura posible mientras mantiene la cantidad de servidores involucrados en el procesamiento de una consulta lo más baja posible.
Sin embargo, algunos patrones aún pueden generar un comportamiento subóptimo de los objetos de escucha de instantáneas. Por ejemplo, si tu app almacena la mayoría de sus datos en una gran colección, el objeto de escucha podría necesitar conectarse a muchos servidores para recibir todos los datos que necesita. Esto sucederá incluso si aplicas un filtro de consulta. Conectarse a muchos servidores aumenta el riesgo de obtener respuestas más lentas.
Si quieres evitar estas respuestas más lentas, diseña el esquema y la app para que el sistema pueda entregar objetos de escucha sin tener que ir a varios servidores diferentes. Puede ser mejor dividir tus datos en colecciones más pequeñas con menores tasas de escritura.
Esto es similar a pensar en las consultas de rendimiento en una base de datos relacional que requieren análisis completos de la tabla. En una base de datos relacional, una consulta que requiere un análisis completo de la tabla es el equivalente de un objeto de escucha de instantáneas que supervisa una colección con deserción alta. Su rendimiento puede ser lento en comparación con una consulta que la base de datos puede entregar mediante un índice más específico. Una consulta con un índice más específico es como un objeto de escucha de instantáneas que supervisa un solo documento o una colección que cambia con menos frecuencia. Debes realizar una prueba de carga de tu app para comprender mejor el comportamiento y las necesidades de tu caso de uso.
Mantén rápidas a las consultas de sondeo
Otra parte clave de las consultas en tiempo real responsivas implica asegurarse de que la consulta de sondeo que iniciará los datos sea rápida y eficiente. La primera vez que se conecta un nuevo objeto de escucha de instantáneas, este debe cargar todo el conjunto de resultados y enviarlo al dispositivo del usuario. Las consultas lentas hacen que tu app sea menos responsiva. Esto incluye, por ejemplo, las consultas que intentan leer muchos documentos o las que no usan los índices adecuados.
Un objeto de escucha también puede regresar de un estado de escucha a uno de sondeo bajo ciertas circunstancias. Esto ocurre automáticamente y es transparente para los SDK y tu app. Las siguientes condiciones pueden activar un estado de sondeo:
- El sistema rebalancea un registro de cambios debido a los cambios en la carga.
- Los hotspots provocan operaciones de escritura fallidas o retrasadas en la base de datos.
- Los reinicios transitorios del servidor afectan a los objetos de escucha de manera temporal.
Si las consultas de sondeo son lo suficientemente rápidas, el estado de sondeo se vuelve transparente para los usuarios de la app.
Prioriza los objetos de escucha de larga duración
Abrir los objetos de escucha y mantenerlos activos durante el mayor tiempo posible suele ser la forma más rentable de compilar una app que use Firestore. Cuando usas Firestore, se te factura por los documentos que se muestran a la app y no por mantener una conexión abierta. Un objeto de escucha de instantáneas de larga duración solo lee los datos que necesita para entregar la consulta a lo largo de su vida útil. Esto incluye una operación de sondeo inicial seguida de notificaciones cuando los datos cambian. Las consultas únicas, por otro lado, vuelven a leer datos que pueden no haber cambiado desde la última vez que la app ejecutó la consulta.
En los casos en los que la app debe consumir una tasa alta de datos, es posible que los objetos de escucha de instantáneas no sean adecuados. Por ejemplo, si tu caso de uso envía muchos documentos por segundo a través de una conexión durante un período prolongado, quizás sea mejor optar por consultas únicas que se ejecutan con una frecuencia menor.
Próximos pasos
- Obtén más información para usar objetos de escucha de instantáneas.
- Obtén más información sobre las prácticas recomendadas.