Práticas recomendadas
Use as práticas recomendadas indicadas aqui como referência rápida ao criar uma aplicação que use o Firestore.
Localização da base de dados
Quando criar a instância da base de dados, selecione a localização da base de dados mais próxima dos seus utilizadores e recursos de computação. Os saltos de rede de longo alcance são mais propensos a erros e aumentam a latência das consultas.
Para maximizar a disponibilidade e a durabilidade da sua aplicação, selecione uma localização em várias regiões e coloque recursos de computação críticos em, pelo menos, duas regiões.
Selecione uma localização regional para custos mais baixos, para uma latência de escrita mais baixa se a sua aplicação for sensível à latência ou para colocação conjunta com outros recursos do GCP.
IDs de documentos
- Evite os IDs de documentos
.
e..
. - Evite usar
/
barras invertidas nos IDs dos documentos. Não use IDs de documentos que aumentam monotonicamente, como:
Customer1
,Customer2
,Customer3
, ...Product 1
,Product 2
,Product 3
, ...
Estes IDs sequenciais podem originar pontos críticos que afetam a latência.
Nomes dos campos
Evite os seguintes carateres nos nomes dos campos, uma vez que requerem carateres de escape adicionais:
.
ponto final[
parêntese reto esquerdo]
Parêntese reto direito*
asterisco`
acento grave
Índices
Reduza a latência de escrita
O principal fator que contribui para a latência de escrita é a ramificação do índice. As práticas recomendadas para reduzir a ramificação do índice são:
Defina isenções de índice ao nível da recolha. Uma predefinição simples é desativar a indexação descendente e de matriz. A remoção de valores indexados não usados também reduz os custos de armazenamento.
Reduza o número de documentos numa transação. Para escrever um grande número de documentos, considere usar um escritor em massa em vez do escritor de lotes atómico.
Isenções de índice
Para a maioria das apps, pode confiar na indexação automática, bem como em quaisquer links de mensagens de erro para gerir os seus índices. No entanto, é aconselhável adicionar exceções de campo único nos seguintes casos:
Caixa | Descrição |
---|---|
Campos de strings grandes | Se tiver um campo de string que contenha frequentemente valores de string longos que não usa para consultas, pode reduzir os custos de armazenamento isentando o campo da indexação. |
Taxas de gravação elevadas numa coleção que contém documentos com valores sequenciais | Se indexar um campo que aumenta ou diminui sequencialmente entre documentos numa coleção, como uma data/hora, a taxa de gravação máxima na coleção é de 500 gravações por segundo. Se não consultar com base no campo com valores sequenciais, pode isentar o campo da indexação para contornar este limite. Num exemplo de utilização de IoT com uma taxa de gravação elevada, uma coleção que contenha documentos com um campo de data/hora pode aproximar-se do limite de 500 gravações por segundo. |
Campos TTL |
Se usar políticas de TTL (tempo de vida), tenha em atenção que o campo TTL tem de ser uma indicação de tempo. A indexação em campos TTL está ativada por predefinição e pode afetar o desempenho a taxas de tráfego mais elevadas. Como prática recomendada, adicione isenções de campo único para os campos TTL. |
Campos de matriz ou mapa grandes | Os campos de matriz ou mapa grandes podem aproximar-se do limite de 40 000 entradas de índice por documento. Se não estiver a consultar com base num campo de matriz ou mapa grande, deve excluí-lo da indexação. |
Operações de leitura e escrita
A taxa máxima exata com que uma app pode atualizar um único documento depende muito da carga de trabalho. Para mais informações, consulte o artigo Atualizações a um único documento.
Use chamadas assíncronas onde estiverem disponíveis em vez de chamadas síncronas. As chamadas assíncronas minimizam o impacto da latência. Por exemplo, considere uma aplicação que precisa do resultado de uma pesquisa de documentos e dos resultados de uma consulta antes de renderizar uma resposta. Se a pesquisa e a consulta não tiverem uma dependência de dados, não é necessário esperar sincronamente até que a pesquisa seja concluída antes de iniciar a consulta.
Não use desvios. Em alternativa, use cursores. A utilização de um deslocamento apenas evita a devolução dos documentos ignorados à sua aplicação, mas estes documentos continuam a ser obtidos internamente. Os documentos ignorados afetam a latência da consulta, e a sua aplicação é faturada pelas operações de leitura necessárias para os obter.
Novas tentativas de transações
Os SDKs e as bibliotecas cliente do Firestore tentam automaticamente novamente as transações com falhas para lidar com erros transitórios. Se a sua aplicação aceder ao Firestore através das APIs REST ou RPC diretamente em vez de através de um SDK, a sua aplicação deve implementar novas tentativas de transação para aumentar a fiabilidade.
Atualizações em tempo real
Para ver as práticas recomendadas relacionadas com atualizações em tempo real, consulte o artigo Compreenda as consultas em tempo real em grande escala.
Conceber para a escalabilidade
As seguintes práticas recomendadas descrevem como evitar situações que criam problemas de contenção.
Atualizações a um único documento
À medida que cria a sua app, considere a rapidez com que a app atualiza documentos individuais. A melhor forma de caracterizar o desempenho da sua carga de trabalho é realizar testes de carga. A taxa máxima exata com que uma app pode atualizar um único documento depende muito da carga de trabalho. Os fatores incluem a taxa de gravação, a contenção entre pedidos e o número de índices afetados.
Uma operação de escrita de documentos atualiza o documento e todos os índices associados, e o Firestore aplica sincronamente a operação de escrita num quórum de réplicas. A taxas de gravação suficientemente elevadas, a base de dados começa a encontrar contenção, latência mais elevada ou outros erros.
Taxas de leitura, escrita e eliminação elevadas num intervalo de documentos restrito
Evite taxas de leitura ou escrita elevadas em documentos lexicograficamente próximos, ou a sua aplicação vai ter erros de contenção. Este problema é conhecido como hotspotting e a sua aplicação pode sofrer hotspotting se fizer alguma das seguintes ações:
Cria novos documentos a uma taxa muito elevada e atribui os seus próprios IDs que aumentam monotonicamente.
O Firestore atribui IDs de documentos através de um algoritmo de dispersão. Não deve encontrar hotspotting em gravações se criar novos documentos com IDs de documentos automáticos.
Cria novos documentos a uma taxa elevada numa coleção com poucos documentos.
Cria novos documentos com um campo de aumento monotónico, como uma data/hora, a uma taxa muito elevada.
Elimina documentos numa coleção a uma taxa elevada.
Escreve na base de dados a uma taxa muito elevada sem aumentar gradualmente o tráfego.
Evite ignorar dados eliminados
Evite consultas que ignorem dados eliminados recentemente. Uma consulta pode ter de ignorar um grande número de entradas de índice se os resultados da consulta iniciais tiverem sido eliminados recentemente.
Um exemplo de uma carga de trabalho que pode ter de ignorar muitos dados eliminados é uma que tente encontrar os itens de trabalho mais antigos na fila. A consulta pode ter o seguinte aspeto:
docs = db.collection('WorkItems').order_by('created').limit(100)
delete_batch = db.batch()
for doc in docs.stream():
finish_work(doc)
delete_batch.delete(doc.reference)
delete_batch.commit()
Sempre que esta consulta é executada, analisa as entradas de índice do campo created
em todos os documentos eliminados recentemente. Isto torna as consultas mais lentas.
Para melhorar o desempenho, use o método start_at
para encontrar o melhor
ponto de partida. Por exemplo:
completed_items = db.collection('CompletionStats').document('all stats').get()
docs = db.collection('WorkItems').start_at(
{'created': completed_items.get('last_completed')}).order_by(
'created').limit(100)
delete_batch = db.batch()
last_completed = None
for doc in docs.stream():
finish_work(doc)
delete_batch.delete(doc.reference)
last_completed = doc.get('created')
if last_completed:
delete_batch.update(completed_items.reference,
{'last_completed': last_completed})
delete_batch.commit()
NOTA: o exemplo acima usa um campo de aumento monótono, que é um antipadrão para taxas de gravação elevadas.
Aumentar o tráfego
Deve aumentar gradualmente o tráfego para novas coleções ou documentos lexicograficamente próximos para dar ao Firestore tempo suficiente para preparar os documentos para o aumento do tráfego. Recomendamos que comece com um máximo de 500 operações por segundo numa nova coleção e, em seguida, aumente o tráfego 50% a cada 5 minutos. Da mesma forma, pode aumentar gradualmente o tráfego de escrita, mas tenha em atenção os limites padrão do Firestore. Certifique-se de que as operações são distribuídas de forma relativamente uniforme ao longo do intervalo de chaves. Isto chama-se a regra "500/50/5".
Migrar tráfego para uma nova coleção
O aumento gradual é particularmente importante se migrar o tráfego de apps de uma coleção para outra. Uma forma simples de processar esta migração é ler a partir da coleção antiga e, se o documento não existir, ler a partir da nova coleção. No entanto, isto pode causar um aumento súbito do tráfego para documentos lexicograficamente próximos na nova coleção. O Firestore pode não conseguir preparar de forma eficiente a nova coleção para um aumento do tráfego, especialmente quando contém poucos documentos.
Pode ocorrer um problema semelhante se alterar os IDs de documentos de muitos documentos na mesma coleção.
A melhor estratégia para migrar tráfego para uma nova recolha depende do seu modelo de dados. Segue-se um exemplo de uma estratégia conhecida como leituras paralelas. Tem de determinar se esta estratégia é eficaz para os seus dados e uma consideração importante é o impacto do custo das operações paralelas durante a migração.
Leituras paralelas
Para implementar leituras paralelas à medida que migra o tráfego para uma nova coleção, leia primeiro a coleção antiga. Se o documento estiver em falta, leia a partir da nova coleção. Uma taxa elevada de leituras de documentos inexistentes pode levar à criação de pontos críticos. Por isso, certifique-se de que aumenta gradualmente a carga para a nova coleção. Uma estratégia melhor é copiar o documento antigo para a nova coleção e, em seguida, eliminar o documento antigo. Aumente as leituras paralelas gradualmente para garantir que o Firestore consegue processar o tráfego para a nova coleção.
Uma possível estratégia para aumentar gradualmente as leituras ou as gravações numa nova coleção é usar um hash determinístico do ID do utilizador para selecionar uma percentagem aleatória de utilizadores que tentam gravar novos documentos. Certifique-se de que o resultado do hash do ID do utilizador não é distorcido pela sua função nem pelo comportamento do utilizador.
Entretanto, execute um trabalho em lote que copie todos os seus dados dos documentos antigos para a nova coleção. A sua tarefa em lote deve evitar escritas em IDs de documentos sequenciais para evitar pontos críticos. Quando a tarefa em lote terminar, só pode ler a partir da nova coleção.
Um refinamento desta estratégia consiste em migrar pequenos lotes de utilizadores de cada vez. Adicione um campo ao documento do utilizador que monitoriza o estado da migração desse utilizador. Selecione um lote de utilizadores para migrar com base num hash do ID do utilizador. Use uma tarefa em lote para migrar documentos para esse lote de utilizadores e use leituras paralelas para utilizadores no meio da migração.
Tenha em atenção que não pode reverter facilmente a migração, a menos que faça escritas duplas das entidades antigas e novas durante a fase de migração. Isto aumentaria os custos incorridos do Firestore.
Privacidade
- Evite armazenar informações confidenciais num ID do projeto na nuvem. Um ID do projeto do Google Cloud pode ser retido após o fim do ciclo de vida do seu projeto.
- Como prática recomendada de conformidade com os dados, recomendamos que não armazene informações confidenciais nos nomes dos documentos e nos nomes dos campos dos documentos.