Bonnes pratiques pour Cloud Firestore

Utilisez les bonnes pratiques répertoriées ici comme référence rapide lors de la création d'une application qui utilise Cloud Firestore.

Emplacement de la base de données

Lorsque vous créez votre instance de base de données, sélectionnez l' emplacement de base de données le plus proche de vos utilisateurs et de vos ressources de calcul. Les sauts de réseau de grande envergure sont plus sujets aux erreurs et augmentent la latence des requêtes.

Pour optimiser la disponibilité et la durabilité de votre application, sélectionnez un emplacement multirégional et placez les ressources de calcul critiques dans au moins deux régions.

Sélectionnez un emplacement régional pour réduire les coûts, pour une latence d'écriture plus faible si votre application est sensible à la latence ou pour une colocalisation avec d'autres ressources GCP .

ID de document

  • Évitez les identifiants de documents . et .. .
  • Évitez d'utiliser / barres obliques dans les identifiants de documents.
  • N'utilisez pas d'ID de document augmentant de manière monotone, tels que :

    • Customer1 , Customer2 , Customer3 , ...
    • Product 1 , Product 2 , Product 3 , ...

    De tels identifiants séquentiels peuvent conduire à des points chauds ayant un impact sur la latence.

Noms des champs

  • Évitez les caractères suivants dans les noms de champs, car ils nécessitent un échappement supplémentaire :

    • . période
    • [ crochet gauche
    • ] support droit
    • * astérisque
    • ` backtick

Index

Réduire la latence d'écriture

Le principal contributeur à la latence d’écriture est la diffusion de l’index. Les meilleures pratiques pour réduire la diffusion de l'index sont :

  • Définir des exemptions d'index au niveau de la collection . Une solution simple par défaut consiste à désactiver l’indexation descendante et Array. La suppression des valeurs indexées inutilisées réduira également les coûts de stockage .

  • Réduisez le nombre de documents dans une transaction. Pour rédiger un grand nombre de documents, envisagez d'utiliser un rédacteur en masse au lieu du rédacteur par lots atomique.

Dispenses d'indice

Pour la plupart des applications, vous pouvez compter sur l'indexation automatique ainsi que sur les liens de messages d'erreur pour gérer vos index. Cependant, vous souhaiterez peut-être ajouter des exemptions pour un seul champ dans les cas suivants :

Cas Description
Grands champs de chaînes

Si vous disposez d'un champ de chaîne contenant souvent des valeurs de chaîne longues que vous n'utilisez pas pour les requêtes, vous pouvez réduire les coûts de stockage en exemptant le champ de l'indexation.

Taux d'écriture élevés dans une collection contenant des documents avec des valeurs séquentielles

Si vous indexez un champ qui augmente ou diminue de manière séquentielle entre les documents d'une collection, comme un horodatage, le taux d'écriture maximal dans la collection est de 500 écritures par seconde. Si vous n'effectuez pas de requête basée sur le champ avec des valeurs séquentielles, vous pouvez exempter le champ de l'indexation pour contourner cette limite.

Dans un cas d'utilisation IoT avec un taux d'écriture élevé, par exemple, une collection contenant des documents avec un champ d'horodatage peut approcher la limite de 500 écritures par seconde.

Champs TTL

Si vous utilisez des politiques TTL (durée de vie) , notez que le champ TTL doit être un horodatage. L'indexation sur les champs TTL est activée par défaut et peut affecter les performances à des taux de trafic plus élevés. Il est recommandé d'ajouter des exemptions pour un seul champ à vos champs TTL.

Grands champs de tableau ou de carte

Les grands champs de tableau ou de carte peuvent approcher la limite de 40 000 entrées d’index par document. Si vous n'effectuez pas de requête sur la base d'un grand tableau ou d'un champ de carte, vous devez l'exempter de l'indexation.

Opérations de lecture et d'écriture

  • La vitesse maximale exacte à laquelle une application peut mettre à jour un seul document dépend fortement de la charge de travail. Pour plus d'informations, voir Mises à jour d'un seul document .

  • Utilisez des appels asynchrones lorsqu'ils sont disponibles au lieu d'appels synchrones. Les appels asynchrones minimisent l’impact de la latence. Par exemple, considérons une application qui a besoin du résultat d’une recherche de document et des résultats d’une requête avant de fournir une réponse. Si la recherche et la requête n'ont pas de dépendance de données, il n'est pas nécessaire d'attendre de manière synchrone la fin de la recherche avant de lancer la requête.

  • N'utilisez pas de décalages. Utilisez plutôt des curseurs . Utiliser un offset évite seulement de renvoyer les documents ignorés à votre application, mais ces documents sont quand même récupérés en interne. Les documents ignorés affectent la latence de la requête et votre application est facturée pour les opérations de lecture nécessaires à leur récupération.

Nouvelles tentatives de transactions

Les SDK Cloud Firestore et les bibliothèques clientes réessayent automatiquement les transactions ayant échoué pour traiter les erreurs passagères. Si votre application accède à Cloud Firestore directement via les API REST ou RPC plutôt que via un SDK, votre application doit implémenter de nouvelles tentatives de transaction pour augmenter la fiabilité.

Mises à jour en temps réel

Pour connaître les bonnes pratiques liées aux mises à jour en temps réel, consultez Comprendre les requêtes en temps réel à grande échelle .

Concevoir à grande échelle

Les bonnes pratiques suivantes décrivent comment éviter les situations qui créent des problèmes de conflit.

Mises à jour d'un seul document

Lorsque vous concevez votre application, tenez compte de la rapidité avec laquelle elle met à jour des documents uniques. La meilleure façon de caractériser les performances de votre charge de travail consiste à effectuer des tests de charge. La vitesse maximale exacte à laquelle une application peut mettre à jour un seul document dépend fortement de la charge de travail. Les facteurs incluent le taux d'écriture, les conflits entre les requêtes et le nombre d'index affectés.

Une opération d'écriture de document met à jour le document et tous les index associés, et Cloud Firestore applique de manière synchrone l'opération d'écriture sur un quorum d'instances dupliquées. À des taux d'écriture suffisamment élevés, la base de données commencera à rencontrer des conflits, une latence plus élevée ou d'autres erreurs.

Taux de lecture, d'écriture et de suppression élevés sur une plage de documents étroite

Évitez les taux de lecture ou d’écriture élevés pour fermer les documents lexicographiquement, sinon votre application rencontrera des erreurs de contention. Ce problème est connu sous le nom de hotspotting, et votre application peut rencontrer un hotspotting si elle effectue l'une des opérations suivantes :

  • Crée de nouveaux documents à un rythme très élevé et attribue ses propres identifiants croissants de manière monotone.

    Cloud Firestore attribue des ID de document à l'aide d'un algorithme de dispersion. Vous ne devriez pas rencontrer de points chauds lors des écritures si vous créez de nouveaux documents à l'aide d'ID de document automatiques.

  • Crée de nouveaux documents à un rythme élevé dans une collection contenant peu de documents.

  • Crée de nouveaux documents avec un champ croissant de manière monotone, comme un horodatage, à une vitesse très élevée.

  • Supprime les documents d'une collection à un rythme élevé.

  • Écrit dans la base de données à un rythme très élevé sans augmenter progressivement le trafic.

Évitez d'ignorer les données supprimées

Évitez les requêtes qui ignorent les données récemment supprimées. Une requête peut devoir ignorer un grand nombre d'entrées d'index si les premiers résultats de la requête ont été récemment supprimés.

Un exemple de charge de travail qui pourrait devoir ignorer un grand nombre de données supprimées est celle qui tente de trouver les éléments de travail les plus anciens en file d'attente. La requête pourrait ressembler à :

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()

Chaque fois que cette requête est exécutée, elle analyse les entrées d'index pour le champ created sur tous les documents récemment supprimés. Cela ralentit les requêtes.

Pour améliorer les performances, utilisez la méthode start_at pour trouver le meilleur point de départ. Par exemple:

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()

REMARQUE : L'exemple ci-dessus utilise un champ croissant de manière monotone qui constitue un anti-modèle pour les taux d'écriture élevés.

Augmentation du trafic

Vous devez augmenter progressivement le trafic vers de nouvelles collections ou fermer les documents de manière lexicographique pour donner à Cloud Firestore suffisamment de temps pour préparer les documents à un trafic accru. Nous recommandons de commencer avec un maximum de 500 opérations par seconde vers une nouvelle collection, puis d'augmenter le trafic de 50 % toutes les 5 minutes. Vous pouvez de la même manière augmenter votre trafic d'écriture, mais gardez à l'esprit les limites standard de Cloud Firestore . Assurez-vous que les opérations sont réparties de manière relativement uniforme sur toute la plage de touches. C’est ce qu’on appelle la règle « 500/50/5 ».

Migration du trafic vers une nouvelle collection

Une montée en puissance progressive est particulièrement importante si vous migrez le trafic d’applications d’une collection à une autre. Un moyen simple de gérer cette migration consiste à lire à partir de l’ancienne collection, et si le document n’existe pas, à lire à partir de la nouvelle collection. Cependant, cela pourrait entraîner une augmentation soudaine du trafic pour fermer lexicographiquement les documents de la nouvelle collection. Cloud Firestore peut ne pas être en mesure de préparer efficacement la nouvelle collection à un trafic accru, en particulier lorsqu'elle contient peu de documents.

Un problème similaire peut se produire si vous modifiez les ID de plusieurs documents au sein de la même collection.

La meilleure stratégie pour migrer le trafic vers une nouvelle collection dépend de votre modèle de données. Vous trouverez ci-dessous un exemple de stratégie connue sous le nom de lectures parallèles . Vous devrez déterminer si cette stratégie est efficace ou non pour vos données, et un facteur important à prendre en compte sera l'impact financier des opérations parallèles lors de la migration.

Lectures parallèles

Pour implémenter des lectures parallèles lors de la migration du trafic vers une nouvelle collection, lisez d’abord l’ancienne collection. Si le document est manquant, lisez la nouvelle collection. Un taux élevé de lectures de documents inexistants peut conduire à des points chauds, alors assurez-vous d'augmenter progressivement la charge de la nouvelle collection. Une meilleure stratégie consiste à copier l'ancien document dans la nouvelle collection, puis à supprimer l'ancien document. Augmentez progressivement les lectures parallèles pour garantir que Cloud Firestore puisse gérer le trafic vers la nouvelle collection.

Une stratégie possible pour augmenter progressivement les lectures ou les écritures dans une nouvelle collection consiste à utiliser un hachage déterministe de l'ID utilisateur pour sélectionner un pourcentage aléatoire d'utilisateurs tentant d'écrire de nouveaux documents. Assurez-vous que le résultat du hachage de l'ID utilisateur n'est pas faussé par votre fonction ou par le comportement de l'utilisateur.

Pendant ce temps, exécutez un travail par lots qui copie toutes vos données des anciens documents vers la nouvelle collection. Votre travail par lots doit éviter les écritures sur des ID de document séquentiels afin d'éviter les points chauds. Une fois le travail par lots terminé, vous pouvez lire uniquement la nouvelle collection.

Un perfectionnement de cette stratégie consiste à migrer de petits lots d'utilisateurs à la fois. Ajoutez un champ au document utilisateur qui suit le statut de migration de cet utilisateur. Sélectionnez un lot d'utilisateurs à migrer en fonction d'un hachage de l'ID utilisateur. Utilisez un travail par lots pour migrer les documents pour ce lot d'utilisateurs et utilisez des lectures parallèles pour les utilisateurs en cours de migration.

Notez que vous ne pouvez pas facilement revenir en arrière, sauf si vous effectuez une double écriture de l'ancienne et de la nouvelle entités pendant la phase de migration. Cela augmenterait les coûts Cloud Firestore engagés.

Confidentialité

  • Évitez de stocker des informations sensibles dans un ID de projet Cloud. Un ID de projet Cloud peut être conservé au-delà de la durée de vie de votre projet.
  • En tant que bonne pratique de conformité des données, nous vous recommandons de ne pas stocker d'informations sensibles dans les noms de documents et les noms de champs de documents.

Empêcher tout accès non autorisé

Empêchez les opérations non autorisées sur votre base de données avec les règles de sécurité Cloud Firestore. Par exemple, l’utilisation de règles pourrait éviter un scénario dans lequel un utilisateur malveillant télécharge à plusieurs reprises l’intégralité de votre base de données.

En savoir plus sur l'utilisation des règles de sécurité Cloud Firestore .