Le téléchargement séquentiel d'un objet volumineux dans Cloud Storage via une seule connexion peut laisser la bande passante réseau disponible inutilisée. En divisant un objet en segments de plage d'octets appelés "bandes" et en lisant ces segments simultanément, vous pouvez améliorer le débit de téléchargement des objets volumineux à l'aide des bibliothèques clientes Cloud pour Rust.
Ce document explique comment amorcer des objets de test volumineux à l'aide de la composition d'objets, télécharger des plages d'octets simultanément avec ReadRange::segment et écrire des bandes dans un fichier local à des décalages fixes. Si vous débutez avec la bibliothèque cliente, consultez d'abord Utiliser Cloud Storage avec Rust.
Avant de commencer
Avant d'exécuter le code de ce document, assurez-vous de remplir les conditions préalables suivantes :
- Créez ou sélectionnez un projetGoogle Cloud pour lequel la facturation est activée.
- Créez un bucket Cloud Storage de test dédié dans votre projet.
- Configurez les identifiants par défaut de l'application pour votre environnement.
- Attribuez à votre compte principal un rôle IAM (Identity and Access Management) avec l'autorisation de lire, d'écrire, de composer et de supprimer des objets dans le bucket, par exemple "Administrateur de l'espace de stockage" (
roles/storage.admin).
Dépendances
Ajoutez la bibliothèque cliente Cloud Storage et les crates compatibles à votre fichier Cargo.toml :
cargo add google-cloud-storage google-cloud-gax anyhow bytes futures
cargo add tokio --features macros,rt-multi-thread
Créer des objets de test volumineux
Pour tester les téléchargements segmentés sans importer des gigaoctets de données sur le réseau, importez un petit objet d'amorçage et utilisez l'opération de composition de Cloud Storage pour concaténer les copies côté serveur. Dans une fonction seed asynchrone qui accepte client, control et bucket_name au format projects/_/buckets/BUCKET_ID, procédez comme suit :
Pour référencer des objets existants dans des requêtes de composition, importez
SourceObject:Importez un objet d'amorçage de 1 Mio nommé
1MiB.txt:Pour créer un objet de 32 Mio nommé
32MiB.txt, concaténez 32 copies de1MiB.txtsur le serveur :Pour créer un objet de 1 Gio nommé
1GiB.txt, concaténez 32 copies de32MiB.txt:Pour créer des objets de test de puissance de deux à partir de
1GiB.txt(2GiB.txt,4GiB.txt,8GiB.txt,16GiB.txtet32GiB.txt), répétez l'opération de composition :
Coordonner les téléchargements de bandes simultanés
Pour télécharger un objet en parallèle, interrogez sa taille et sa génération, préallouez le fichier de destination local et générez un futur par bande. Dans une fonction download qui accepte client, control, bucket_name, object_name, stripe_size et destination, procédez comme suit :
Récupérez les métadonnées de l'objet à l'aide de
StorageControl::get_objectafin de pouvoir inspecter la taille totale de l'objet et verrouiller les lectures ultérieures sur une seule génération :Créez le fichier de destination et préallouez-le à la taille exacte de l'objet afin que les tâches de nœud de calcul puissent écrire à des décalages d'octets indépendants :
Calculez chaque décalage de bande en utilisant
stripe_sizecommelimitet créez un futurwrite_stripepar segment, en ajoutant une bande partielle finale lorsque la taille de l'objet n'est pas divisible de manière égale parlimit:Exécutez tous les objets Future de bande simultanément avec
futures::future::join_allet propagez les erreurs :
Télécharger et écrire une bande individuelle
Chaque tâche write_stripe lit une seule plage d'octets à partir de Cloud Storage et écrit les fragments reçus au décalage correspondant dans le handle de fichier local partagé. Pour implémenter write_stripe, procédez comme suit :
Importez
ReadRangeet définissez la fonctionwrite_stripe:Créez un générateur de requêtes
ReadObjectavecStorage::read_object, puis envoyez la requête après avoir configuré les options de génération et de plage de lecture en procédant comme suit :Pour épingler toutes les bandes à la même génération d'objet et éviter les lectures incohérentes si un autre processus écrase l'objet, appelez
set_generationsur le compilateur de requêtes avant d'appelersend:Pour limiter la lecture à la plage d'octets de la bande, appelez
set_read_rangeavecReadRange::segment(offset, limit)sur le compilateur de requêtes :Diffusez des fragments à partir du lecteur et écrivez chaque fragment dans le fichier de destination à l'emplacement
current_posdanstokio::task::spawn_blocking. Étant donné que la bibliothèque standard de Rust ne dispose pas d'une méthode d'écriture positionnelle multiplate-forme, cet exemple utiliseFileExt::write_all_atsous Unix etFileExt::seek_writesous Windows :
Considérations sur les performances
Plusieurs facteurs déterminent le débit effectif des téléchargements segmentés :
- Vitesse du disque local. L'écriture de fragments sur un espace de stockage local lent peut devenir un goulot d'étranglement. L'utilisation d'un stockage SSD local à haut débit permet de maintenir les E/S de disque en avance sur les lectures réseau.
- Capacité de processeur de la VM. Cloud Storage chiffre les données d'objet en transit. Le client déchiffre donc chaque fragment qu'il reçoit. Assurez-vous que votre VM dispose de suffisamment de processeurs virtuels pour gérer le déchiffrement TLS simultané sur les bandes.
- Emplacement du bucket et de la VM. Le téléchargement entre régions entraîne une latence du réseau étendu et limite le débit. Colocalisez votre VM dans la même région que votre bucket lorsque cela est possible.
Vous pouvez également essayer d'ajuster stripe_size pour éviter de laisser une bande restante très petite ou de créer trop de petites requêtes de plage.
Compléter le code
L'exemple suivant combine les fonctions seed, download et write_stripe dans un module complet :
Lorsque vous exécutez download sur un objet de 32 Mio avec un stripe_size de 1 Mio, le résultat ressemble à ce qui suit, indiquant la taille téléchargée, le temps écoulé, le nombre de bandes et la bande passante effective :
Completed 32.00 MiB download in 412.5ms, using 32 stripes, effective bandwidth = 77.58 MiB/s
Effectuer un nettoyage
Pour éviter que les objets de test créés par seed ne soient facturés sur votre compte Google Cloud , supprimez les objets de test et supprimez votre bucket de test lorsque vous avez terminé. Supprimez également le fichier de destination local.