Bonnes pratiques concernant l'API BigQuery Storage en écriture

Ce document présente les bonnes pratiques pour utiliser l'API BigQuery Storage Write. Avant de lire ce document, consultez la Présentation de l'API BigQuery Storage en écriture.

Limiter le taux de création de flux

Avant de créer un flux, déterminez si vous pouvez utiliser le flux par défaut. Dans les scénarios de streaming, le flux par défaut présente moins de limites de quota et peut évoluer mieux que les flux créés par l'application. Si vous utilisez un flux créé par l'application, veillez à utiliser le débit maximal sur chaque flux avant de créer des flux supplémentaires. Par exemple, utilisez des écritures asynchrones.

Pour les flux créés par l'application, évitez d'appeler CreateWriteStream à une fréquence élevée. En général, si vous dépassez 40 à 50 appels par seconde, la latence des appels d'API augmente considérablement (> 25 s). Assurez-vous que votre application peut accepter un démarrage à froid et augmenter progressivement le nombre de flux, et limiter le taux d'appels de CreateWriteStream. Vous pouvez également définir un délai plus long pour attendre la fin de l'appel, afin qu'il n'échoue pas avec une erreur DeadlineExceeded. Il existe également un quota à plus long terme sur le tarif maximal des appels CreateWriteStream. La création de flux est un processus gourmand en ressources. Par conséquent, réduire le taux de création de flux et utiliser pleinement les flux existants constitue le meilleur moyen de ne pas dépasser cette limite.

Gestion des pools de connexions

La méthode AppendRows crée une connexion bidirectionnelle à un flux. Vous pouvez ouvrir plusieurs connexions sur le flux par défaut, mais seulement une connexion active sur des flux créés par l'application.

Lorsque vous utilisez le flux par défaut, vous pouvez utiliser le multiplexage de l'API Storage Write pour écrire dans plusieurs tables de destination avec des connexions partagées. Le multiplexage des connexions de pools permet d'améliorer le débit et l'utilisation des ressources. Si votre workflow comporte plus de 20 connexions simultanées, nous vous recommandons d'utiliser le multiplexage. Le multiplexage est disponible en Java et en Go. Pour en savoir plus sur la mise en œuvre de Java, consultez la page Utiliser le multiplexage. Pour en savoir plus sur la mise en œuvre de Go, consultez la page Partage de connexion (multiplexage).

Pour des performances optimales, utilisez une connexion pour autant d'écritures de données que possible. N'utilisez pas une connexion pour une seule écriture. De même, pour de nombreuses petites écritures, évitez de procéder à l'ouverture et la fermeture de flux.

Il existe un quota sur le nombre de connexions simultanées pouvant être ouvertes simultanément par projet. Au-delà de la limite, les appels à AppendRows échouent. Toutefois, le quota de connexions simultanées peut être augmenté et ne devrait normalement pas être un facteur limitant pour le scaling.

Chaque appel à AppendRows crée un objet de rédacteur de données. Ainsi, lorsque vous utilisez un flux créé par l'application, le nombre de connexions correspond au nombre de flux créés. En règle générale, une seule connexion accepte un débit d'au moins 1 Mbit/s. La limite supérieure dépend de plusieurs facteurs, tels que la bande passante réseau, le schéma des données et la charge du serveur, mais elle peut dépasser 10 Mo/s.

Il existe également un quota sur le débit total par projet. Cela représente les octets par seconde pour toutes les connexions qui transitent par le service de l'API Storage Write. Si votre projet dépasse ce quota, vous pouvez demander une augmentation de limite de quota. En règle générale, cela implique d'augmenter d'un même facteur les quotas associés, tels que le quota de connexions simultanées.

Gérer les décalages de flux pour obtenir une sémantique de type "exactement une fois"

L'API Storage Write n'autorise les écritures qu'à la fin actuelle du flux, qui est déplacée lorsque les données sont ajoutées. La position actuelle dans le flux est spécifiée en tant que décalage par rapport au début du flux.

Lorsque vous écrivez des données dans un flux créé par une application, vous pouvez spécifier le décalage de flux pour obtenir une sémantique d'écriture de type "exactement une fois".

Lorsque vous spécifiez un décalage, l'opération d'écriture est idempotente, ce qui permet de réessayer en toute sécurité en raison d'erreurs réseau ou de l'absence de réponse du serveur. Gérez les erreurs suivantes liées aux décalages:

  • ALREADY_EXISTS (StorageErrorCode.OFFSET_ALREADY_EXISTS) : la ligne a déjà été écrite. Vous pouvez ignorer cette erreur en toute sécurité.
  • OUT_OF_RANGE (StorageErrorCode.OFFSET_OUT_OF_RANGE): une opération d'écriture précédente a échoué. Réessayez à partir de la dernière écriture réussie.

Notez que ces erreurs peuvent également se produire si vous définissez une valeur de décalage incorrecte. Vous devez donc gérer les décalages avec soin.

Avant d'utiliser des décalages de flux, déterminez si vous avez besoin d'une sémantique de type "exactement une fois". Par exemple, si votre pipeline de données en amont garantit uniquement des écritures de type "au moins une fois" ou si vous pouvez facilement détecter les doubles après l'ingestion de données, il est possible que vous n'ayez pas besoin d'écritures de type "exactement une fois". Dans ce cas, nous vous recommandons d'utiliser le flux par défaut, qui ne nécessite pas de suivre les décalages de ligne.

Ne bloquez pas les appels AppendRows.

La méthode AppendRows est asynchrone. Vous pouvez envoyer une série d'écritures sans bloquer de réponse individuellement pour chaque écriture. Les messages de réponse sur la connexion bidirectionnelle arrivent dans le même ordre que les requêtes mises en file d'attente. Pour obtenir la valeur la plus élevée tout au long, appelez AppendRows sans bloquer l'attente de la réponse.

Gérer les mises à jour de schéma

Pour les scénarios de streaming de données, les schémas de table sont généralement gérés en dehors du pipeline de streaming. Il est courant que le schéma évolue au fil du temps, par exemple en ajoutant de nouveaux champs pouvant être vides. Un pipeline robuste doit gérer les mises à jour de schéma hors bande.

L'API Storage Write est compatible avec les schémas de table comme suit:

  • La première requête d'écriture inclut le schéma.
  • Vous envoyez chaque ligne de données en tant que tampon de protocole binaire. BigQuery mappe les données avec le schéma.
  • Vous pouvez omettre les champs pouvant être vides, mais vous ne pouvez pas inclure de champs qui ne sont pas présents dans le schéma actuel. Si vous envoyez des lignes avec des champs supplémentaires, l'API Storage Write renvoie une réponse StorageError avec StorageErrorCode.SCHEMA_MISMATCH_EXTRA_FIELD.

Si vous souhaitez envoyer de nouveaux champs dans la charge utile, vous devez d'abord mettre à jour le schéma de la table dans BigQuery. L'API Storage Write détecte les modifications de schéma après un court instant, de l'ordre de quelques minutes. Lorsque l'API Storage Write détecte la modification de schéma, le message de réponse AppendRowsResponse contient un objet TableSchema qui décrit le nouveau schéma.

Pour envoyer des données à l'aide du schéma mis à jour, vous devez fermer les connexions existantes et ouvrir de nouvelles connexions avec le nouveau schéma.

Client Java : La bibliothèque cliente Java fournit des fonctionnalités supplémentaires pour les mises à jour de schéma, via la classe JsonStreamWriter. Après une mise à jour de schéma, JsonStreamWriter se reconnecte automatiquement au schéma mis à jour. Vous n'avez pas besoin de fermer puis rouvrir explicitement la connexion. Pour vérifier les modifications de schéma par programmation, appelez AppendRowsResponse.hasUpdatedSchema une fois la méthode append terminée.

Vous pouvez également configurer JsonStreamWriter pour ignorer les champs inconnus dans les données d'entrée. Pour définir ce comportement, appelez setIgnoreUnknownFields. Ce comportement est similaire à l'option ignoreUnknownValues lorsque vous utilisez l'ancienne API tabledata.insertAll. Cependant, cela peut entraîner une perte de données involontaire, car les champs inconnus sont ignorés sans notification.