Entenda as consultas em tempo real em escala

Leia este documento para obter orientação sobre como dimensionar seu aplicativo sem servidor além de milhares de operações por segundo ou centenas de milhares de usuários simultâneos. Este documento inclui tópicos avançados para ajudá-lo a compreender o sistema em profundidade. Se você está apenas começando com o Cloud Firestore, consulte o guia de início rápido .

O Cloud Firestore e os SDKs móveis/web do Firebase fornecem um modelo poderoso para o desenvolvimento de aplicativos sem servidor em que o código do lado do cliente acessa diretamente o banco de dados. Os SDKs permitem que os clientes ouçam atualizações dos dados em tempo real. Você pode usar atualizações em tempo real para criar aplicativos responsivos que não exijam infraestrutura de servidor. Embora seja muito fácil colocar algo em funcionamento, é útil entender as restrições nos sistemas que compõem o Cloud Firestore para que seu aplicativo sem servidor seja dimensionado e tenha um bom desempenho quando o tráfego aumentar.

Consulte as seções a seguir para obter conselhos sobre como dimensionar seu aplicativo.

Escolha um local de banco de dados próximo aos seus usuários

O diagrama a seguir demonstra a arquitetura de um aplicativo em tempo real:

Exemplo de arquitetura de aplicativo em tempo real

Quando um aplicativo em execução no dispositivo de um usuário (móvel ou web) estabelece uma conexão com o Cloud Firestore, a conexão é roteada para um servidor front-end do Cloud Firestore na mesma região onde seu banco de dados está localizado. Por exemplo, se seu banco de dados estiver em us-east1 , a conexão também vai para um frontend do Cloud Firestore também em us-east1 . Essas conexões são duradouras e permanecem abertas até serem explicitamente fechadas pelo aplicativo. O front-end lê dados dos sistemas de armazenamento subjacentes do Cloud Firestore.

A distância entre a localização física de um usuário e a localização do banco de dados do Cloud Firestore afeta a latência experimentada pelo usuário. Por exemplo, um usuário na Índia cujo aplicativo se comunica com um banco de dados em uma região do Google Cloud na América do Norte pode achar a experiência mais lenta e o aplicativo menos ágil do que se o banco de dados estivesse localizado mais próximo, como na Índia ou em outra parte da Ásia. .

Projete para confiabilidade

Os tópicos a seguir melhoram ou afetam a confiabilidade do seu app:

Ativar modo off-line

Os SDKs do Firebase fornecem persistência de dados off-line. Se o app no ​​dispositivo do usuário não conseguir se conectar ao Cloud Firestore, o app continuará utilizável trabalhando com dados armazenados em cache localmente. Isso garante o acesso aos dados mesmo quando os usuários experimentam conexões de Internet irregulares ou perdem completamente o acesso por várias horas ou dias. Para obter mais detalhes sobre o modo offline, consulte Habilitar dados offline .

Entenda as novas tentativas automáticas

Os SDKs do Firebase cuidam de repetir operações e restabelecer conexões interrompidas. Isso ajuda a solucionar erros transitórios causados ​​pela reinicialização de servidores ou problemas de rede entre o cliente e o banco de dados.

Escolha entre locais regionais e multirregionais

Existem várias vantagens e desvantagens ao escolher entre locais regionais e multirregionais. A principal diferença é como os dados são replicados. Isso impulsiona as garantias de disponibilidade do seu aplicativo. Uma instância multirregional oferece maior confiabilidade de serviço e aumenta a durabilidade dos seus dados, mas a compensação é o custo.

Entenda o sistema de consulta em tempo real

Consultas em tempo real, também chamadas de ouvintes de instantâneo, permitem que o aplicativo ouça alterações no banco de dados e receba notificações de baixa latência assim que os dados forem alterados. Um aplicativo pode obter o mesmo resultado pesquisando periodicamente o banco de dados em busca de atualizações, mas geralmente é mais lento, mais caro e requer mais código. Para obter exemplos de como configurar e usar consultas em tempo real, consulte Obter atualizações em tempo real . As seções a seguir detalham como funcionam os ouvintes de snapshots e descrevem algumas das práticas recomendadas para dimensionar consultas em tempo real e, ao mesmo tempo, manter o desempenho.

Imagine dois usuários que se conectam ao Cloud Firestore por meio de um aplicativo de mensagens criado com um dos SDKs móveis.

O cliente A escreve no banco de dados para adicionar e atualizar documentos em uma coleção chamada chatroom :

collection chatroom:
    document message1:
      from: 'Sparky'
      message: 'Welcome to Cloud Firestore!'

    document message2:
      from: 'Santa'
      message: 'Presents are coming'

O cliente B escuta atualizações na mesma coleção usando um ouvinte de instantâneo. O cliente B recebe uma notificação imediata sempre que alguém cria uma nova mensagem. O diagrama a seguir mostra a arquitetura por trás de um ouvinte de snapshot:

Arquitetura de uma conexão de ouvinte de instantâneo

A seguinte sequência de eventos ocorre quando o Cliente B conecta um ouvinte de snapshot ao banco de dados:

  1. O cliente B abre uma conexão com o Cloud Firestore e registra um listener fazendo uma chamada para onSnapshot(collection("chatroom")) por meio do SDK do Firebase. Este ouvinte pode permanecer ativo por horas.
  2. O front-end do Cloud Firestore consulta o sistema de armazenamento subjacente para inicializar o conjunto de dados. Ele carrega todo o conjunto de resultados de documentos correspondentes. Chamamos isso de consulta de pesquisa . O sistema então avalia as regras de segurança do Firebase do banco de dados para verificar se o usuário pode acessar esses dados. Se o usuário estiver autorizado, o banco de dados retornará os dados ao usuário.
  3. A consulta do cliente B passa então para o modo de escuta . O ouvinte se registra em um manipulador de assinatura e aguarda atualizações nos dados.
  4. O cliente A agora envia uma operação de gravação para modificar um documento.
  5. O banco de dados confirma a alteração do documento em seu sistema de armazenamento.
  6. Transacionalmente, o sistema confirma a mesma atualização em um changelog interno. O changelog estabelece uma ordem estrita de mudanças conforme elas acontecem.
  7. O changelog, por sua vez, distribui os dados atualizados para um conjunto de manipuladores de assinaturas.
  8. Uma correspondência de consulta reversa é executada para verificar se o documento atualizado corresponde a algum ouvinte de snapshot atualmente registrado. Neste exemplo, o documento corresponde ao ouvinte de instantâneo do Cliente B. Como o nome indica, você pode pensar na correspondência de consulta reversa como uma consulta normal ao banco de dados, mas feita ao contrário. Em vez de pesquisar documentos para encontrar aqueles que correspondem a uma consulta, ele pesquisa com eficiência as consultas para encontrar aqueles que correspondem a um documento recebido. Ao encontrar uma correspondência, o sistema encaminha o documento em questão para os ouvintes de snapshot. Em seguida, o sistema avalia as regras de segurança do Firebase do banco de dados para garantir que apenas usuários autorizados recebam os dados.
  9. O sistema encaminha a atualização do documento para o SDK no dispositivo do cliente B e o retorno de chamada onSnapshot é acionado. Se a persistência local estiver habilitada, o SDK também aplicará a atualização ao cache local.

Uma parte importante da escalabilidade do Cloud Firestore depende da distribuição do changelog para os manipuladores de assinatura e os servidores front-end. A distribuição permite que uma única alteração de dados se propague com eficiência para atender milhões de consultas em tempo real e usuários conectados. Ao executar muitas réplicas de todos esses componentes em diversas zonas (ou em diversas regiões, no caso de uma implantação multirregional), o Cloud Firestore alcança alta disponibilidade e escalabilidade.

Vale ressaltar que todas as operações de leitura emitidas por SDKs móveis e web seguem o modelo acima. Eles realizam uma consulta de pesquisa seguida pelo modo de escuta para manter garantias de consistência. Isso também se aplica a ouvintes em tempo real, chamadas para recuperar um documento e consultas únicas . Você pode pensar em recuperações de documentos únicos e consultas únicas como ouvintes de instantâneos de curta duração que vêm com restrições semelhantes em relação ao desempenho.

Aplique as práticas recomendadas para dimensionar consultas em tempo real

Aplique as práticas recomendadas a seguir para criar consultas escalonáveis ​​em tempo real.

Entenda o alto tráfego de gravação no sistema

Esta seção ajuda você a entender como o sistema responde a um número crescente de solicitações de gravação.

Os changelogs do Cloud Firestore que orientam as consultas em tempo real são escalonados horizontalmente automaticamente à medida que o tráfego de gravação aumenta. À medida que a taxa de gravação de um banco de dados aumenta além do que um único servidor pode suportar, o changelog é dividido em vários servidores e o processamento da consulta começa a consumir dados de vários manipuladores de assinatura em vez de um. Do ponto de vista do cliente e do SDK, tudo isso é transparente e nenhuma ação é necessária do aplicativo quando ocorrem divisões. O diagrama a seguir demonstra como as consultas em tempo real são dimensionadas:

Arquitetura de fan-out do changelog

O escalonamento automático permite aumentar o tráfego de gravação sem limites, mas à medida que o tráfego aumenta, o sistema pode levar algum tempo para responder. Siga as recomendações da regra 5-5-5 para evitar a criação de um ponto de acesso de gravação. Key Visualizer é uma ferramenta útil para analisar pontos de acesso de gravação.

Muitos aplicativos têm crescimento orgânico previsível, que o Cloud Firestore pode acomodar sem precauções. No entanto, cargas de trabalho em lote, como a importação de um grande conjunto de dados, podem aumentar as gravações muito rapidamente. Ao projetar seu aplicativo, fique atento à origem do tráfego de gravação.

Entenda como as escritas e as leituras interagem

Você pode pensar no sistema de consulta em tempo real como um pipeline que conecta operações de gravação com leitores. Sempre que um documento é criado, atualizado ou excluído, a alteração se propaga do sistema de armazenamento para os ouvintes atualmente registrados. A estrutura de changelog do Cloud Firestore garante forte consistência, o que significa que seu aplicativo nunca recebe notificações de atualizações fora de ordem em comparação com quando o banco de dados confirmou as alterações de dados. Isso simplifica o desenvolvimento de aplicativos, removendo casos extremos em torno da consistência dos dados.

Esse pipeline conectado significa que uma operação de gravação que causa pontos de acesso ou contenção de bloqueio pode afetar negativamente as operações de leitura. Quando as operações de gravação falham ou sofrem limitação, uma leitura pode parar aguardando dados consistentes do changelog. Se isso acontecer no seu aplicativo, você poderá ver operações de gravação lentas e tempos de resposta lentos correlacionados para consultas. Evitar pontos de acesso é a chave para evitar esse problema.

Mantenha os documentos e as operações de gravação pequenas

Ao criar aplicativos com ouvintes de snapshot, normalmente você deseja que os usuários descubram rapidamente as alterações de dados. Para conseguir isso, tente manter as coisas pequenas. O sistema pode enviar pequenos documentos com dezenas de campos muito rapidamente. Documentos maiores com centenas de campos e grandes dados demoram mais para serem processados.

Da mesma forma, dê preferência a operações de confirmação e gravação curtas e rápidas para manter a latência baixa. Lotes grandes podem proporcionar maior rendimento do ponto de vista do gravador, mas podem, na verdade, aumentar o tempo de notificação para ouvintes de instantâneos. Muitas vezes, isso é contra-intuitivo em comparação com o uso de outros sistemas de banco de dados nos quais você pode usar lotes para melhorar o desempenho.

Use ouvintes eficientes

À medida que as taxas de gravação do seu banco de dados aumentam, o Cloud Firestore divide o processamento de dados em vários servidores. O algoritmo de fragmentação do Cloud Firestore tenta colocar dados da mesma coleção ou grupo de coleções no mesmo servidor de changelog. O sistema tenta maximizar o rendimento de gravação possível, mantendo o número de servidores envolvidos no processamento de uma consulta o mais baixo possível.

No entanto, certos padrões ainda podem levar a um comportamento abaixo do ideal para ouvintes de snapshots. Por exemplo, se seu aplicativo armazena a maioria dos dados em uma grande coleção, o ouvinte pode precisar se conectar a vários servidores para receber todos os dados necessários. Isso permanece verdadeiro mesmo se você aplicar um filtro de consulta. Conectar-se a muitos servidores aumenta o risco de respostas mais lentas.

Para evitar essas respostas mais lentas, projete seu esquema e aplicativo para que o sistema possa atender os ouvintes sem precisar passar por muitos servidores diferentes. Talvez funcione melhor dividir seus dados em coleções menores com taxas de gravação menores.

Isso é semelhante a pensar nas consultas de desempenho em um banco de dados relacional que exigem varreduras completas da tabela. Em um banco de dados relacional, uma consulta que requer uma varredura completa da tabela é equivalente a um ouvinte de instantâneo que observa uma coleção com alta rotatividade. Ele pode ter um desempenho lento em comparação com uma consulta que o banco de dados pode atender usando um índice mais específico. Uma consulta com um índice mais específico é como um ouvinte de instantâneo que observa um único documento ou uma coleção que muda com menos frequência. Você deve testar a carga do seu aplicativo para entender melhor o comportamento e a necessidade do seu caso de uso.

Mantenha as pesquisas rápidas

Outra parte importante das consultas responsivas em tempo real envolve garantir que a consulta de pesquisa para inicializar os dados seja rápida e eficiente. Na primeira vez que um novo ouvinte de snapshot se conecta, o ouvinte deve carregar todo o conjunto de resultados e enviá-lo ao dispositivo do usuário. Consultas lentas tornam seu aplicativo menos responsivo. Isto inclui, por exemplo, consultas que tentam ler muitos documentos ou consultas que não utilizam os índices apropriados.

Um ouvinte também pode voltar de um estado de escuta para um estado de pesquisa em algumas circunstâncias. Isso acontece automaticamente e é transparente para os SDKs e seu aplicativo. As seguintes condições podem desencadear um estado de sondagem:

  • O sistema reequilibra um changelog devido a alterações na carga.
  • Os pontos de acesso causam falhas ou atrasos nas gravações no banco de dados.
  • As reinicializações transitórias do servidor afetam temporariamente os ouvintes.

Se suas consultas de sondagem forem rápidas o suficiente, um estado de sondagem se tornará transparente para os usuários do seu aplicativo.

Favoreça ouvintes longevos

Abrir e manter os ouvintes ativos pelo maior tempo possível costuma ser a maneira mais econômica de criar um aplicativo que usa o Cloud Firestore. Ao usar o Cloud Firestore, você é cobrado pelos documentos devolvidos ao seu aplicativo e não pela manutenção de uma conexão aberta. Um ouvinte de instantâneo de longa duração lê apenas os dados necessários para atender à consulta durante todo o seu tempo de vida. Isso inclui uma operação de pesquisa inicial seguida de notificações quando os dados realmente mudam. As consultas únicas, por outro lado, relêem dados que podem não ter sido alterados desde a última vez que o aplicativo executou a consulta.

Nos casos em que seu aplicativo precisa consumir uma alta taxa de dados, os listeners de snapshot podem não ser apropriados. Por exemplo, se o seu caso de uso envia muitos documentos por segundo através de uma conexão por um longo período de tempo, talvez seja melhor optar por consultas únicas que são executadas em uma frequência mais baixa.

Qual é o próximo