Vos transferts entre une VM GCE et un bucket Cloud Storage sont anormalement lents ? Lisez la suite pour découvrir comment maximiser le débit en upload comme en download, sur des VM Linux et Windows.
Vue d'ensemble
Récemment, un client de DoiT International m'a demandé pourquoi les données stockées sur le SSD local d'un Windows Server hébergé sur Google Compute Engine (ci-après GCE) s'envoyaient vers un bucket Cloud Storage bien plus lentement que prévu. Au départ, je pensais simplement effectuer un benchmark rapide des commandes gsutil pour démontrer l'efficacité des arguments recommandés par la documentation GCP. Au lieu de cela, ce coup d'œil rapide s'est transformé en enquête approfondie sur les performances de transfert entre GCE et GCS, tant mes premiers résultats étaient inhabituels et inattendus.

Si vous voulez simplement connaître les meilleures méthodes pour déplacer des données entre GCE et GCS sur une machine Linux ou Windows, rendez-vous directement à la section Conclusions sur l'utilisation efficace des outils de transfert.
Si en revanche vous souhaitez vous gratter la tête face aux débits étranges et souvent contre-intuitifs obtenus avec les commandes et arguments les plus courants, restez avec moi : nous allons explorer en détail ce qui m'a conduit à la synthèse de recommandations en fin d'article.
Performances d'une VM Linux avec gsutil : gros fichiers
Bien que la demande du client portât sur un transfert depuis un Windows Server, j'ai d'abord effectué les benchmarks là où je me sens le plus à l'aise :
Linux, via l'image publique GCE Debian GNU/Linux 10 (buster).
Le client tentant déjà des transferts depuis des SSD locaux, et souhaitant minimiser les risques que des disques en réseau influencent les vitesses de transfert, j'ai configuré deux tailles de VM, n2-standard-4 et n2-standard-80, chacune équipée d'un SSD local sur lequel les benchmarks seront exécutés.
Le bucket GCS utilisé, ainsi que toutes les VM décrites dans cet article, sont créés en tant que ressources régionales situées dans us-central1.
Pour reproduire l'expérience du client lors du transfert d'un gros fichier, j'ai créé un fichier vide de 30 Go :
fallocate -l 30G temp_30GB_file
J'ai ensuite testé deux paramètres gsutil couramment recommandés :
-m: effectue une copie multi-thread parallèle. Utile pour transférer un grand nombre de fichiers en parallèle, mais pas pour l'upload d'un fichier unique.-o GSUtil:parallel_composite_upload_threshold=150M: découpe les fichiers dépassant le seuil indiqué en plusieurs parties uploadées en parallèle, puis recombinées une fois toutes les parties transférées.
Les performances maximales estimées du SSD local sur les deux VM sont les suivantes :

Limites de débit en lecture/écriture du SSD local
Nous devrions donc pouvoir atteindre jusqu'à 660 Mo/s en lecture et 350 Mo/s en écriture avec gsutil. Voyons ce que les benchmarks d'upload ont révélé :
time gsutil cp temp_30GB_file gs://doit-speed-test-bucket/
# n2-standard-4: 2m21.893s, 216.50 MB/s
# n2-standard-80: 2m11.676s, 233.30 MB/stime gsutil -m cp temp_30GB_file gs://doit-speed-test-bucket/
# n2-standard-4: 2m48.710s, 182.09 MB/s
# n2-standard-80: 2m29.348s, 205.69 MB/stime gsutil -o GSUtil:parallel_composite_upload_threshold=150M cp temp_30GB_file gs://doit-speed-test-bucket/
# n2-standard-4: 1m40.104s, 306.88 MB/s
# n2-standard-80: 0m52.145s, 589.13 MB/stime gsutil -m -o GSUtil:parallel_composite_upload_threshold=150M cp temp_30GB_file gs://doit-speed-test-bucket/
# n2-standard-4: 1m44.579s, 293.75 MB/s
# n2-standard-80: 0m51.154s, 600.54 MB/s
Comme l'indique la documentation gsutil de GCP, les uploads de gros fichiers gagnent à inclure -o GSUtil. Avec davantage de vCPU disponibles pour assister l'upload parallèle des parties, le temps de transfert s'améliore considérablement : avec 600 Mo/s en upload sur la n2-standard-80, on s'approche du débit maximal du SSD (660 Mo/s). Ajouter -m pour un seul fichier ne réduit le temps que de quelques secondes. Jusqu'ici, rien d'anormal.
Passons aux benchmarks de download :
time gsutil cp gs://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 8m3.186s, 63.58 MB/s
# n2-standard-80: 6m13.585, 82.23 MB/stime gsutil -m cp gs://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 7m57.881s, 64.28 MB/s
# n2-standard-80: 6m20.131s, 80.81 MB/s

Attendez un instant…
Les performances de download sur la VM à 80 vCPU n'atteignent que 23 % du débit maximal d'écriture du SSD local. De plus, alors que le multi-threading via -m n'apporte rien pour ce download de fichier unique, et que les deux machines exploitent largement moins que leur débit maximal (10 Gbps pour la n2-standard-4, 32 Gbps pour la n2-standard-80), passer à une machine plus puissante de la même famille ne donne qu'environ 30 % d'amélioration du débit. Étrange — mais pas autant que d'obtenir seulement un quart du débit d'écriture du SSD avec une VM aussi onéreuse.
Que se passe-t-il ?
Après de longues recherches sur le sujet, je n'ai trouvé aucune réponse, mais j'ai découvert s5cmd, un outil conçu pour accélérer drastiquement les uploads et downloads vers les buckets S3. Il revendique une exécution 12 fois plus rapide que les commandes équivalentes de l'AWS CLI (par ex. aws s3 cp), notamment parce qu'il est écrit en Go, un langage compilé, alors que l'AWS CLI est écrit en Python. Or, gsutil est lui aussi écrit en Python. Peut-être gsutil est-il fortement pénalisé par ce choix de langage, ou simplement mal optimisé ? Sachant que les buckets GCS peuvent être configurés avec l'interopérabilité S3, est-il possible d'accélérer les transferts avec s5cmd en passant simplement par un outil compilé ?
Performances d'une VM Linux avec s5cmd : gros fichiers
Mettre s5cmd en route a demandé un peu d'effort : j'ai notamment dû découvrir à mes dépens que l'interopérabilité GCS ne prend pas en charge l'API multipart upload de S3. Comme l'outil est conçu uniquement pour AWS, il échoue sur les uploads de gros fichiers vers GCP. Il faut fournir -p=1000000, un argument qui force l'outil à éviter le multipart upload. Voir les issues s5cmd #1 et #2 pour plus d'informations.
Notez que s5cmd propose aussi un paramètre -c pour définir le nombre de parties/fichiers transférés simultanément, avec une valeur par défaut de 5.
Avec ces deux arguments à l'esprit, voici les benchmarks d'upload Linux :
time s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 temp_30GB_file s3://doit-speed-test-bucket/
# n2-standard-4: 6m7.459s, 83.60 MB/s
# n2-standard-80: 6m50.272s, 74.88 MB/stime s5cmd --endpoint-url https://storage.googleapis.com cp -p=1000000 temp_30GB_file s3://doit-speed-test-bucket/
# n2-standard-4: 7m18.682s, 70.03 MB/s
# n2-standard-80: 6m48.380s, 75.22 MB/s
Comme prévu, les uploads de gros fichiers sont nettement moins performants que ceux de gsutil, faute de stratégie multipart. On observe 75 à 85 Mo/s contre 200 à 600 Mo/s pour gsutil. Forcer une concurrence de 1 plutôt que la valeur par défaut de 5 n'a qu'un faible impact. s5cmd traitant AWS comme une plateforme de premier rang sans considération pour GCP, il n'est donc pas envisageable de l'utiliser pour accélérer les uploads.
Voici les benchmarks de download avec s5cmd :
time s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 1m56.170s, 264.44 MB/s
# n2-standard-80: 1m46.196s, 289.28 MB/stime s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 s3://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 3m21.380s, 152.55 MB/s
# n2-standard-80: 3m45.414s, 136.28 MB/stime s5cmd --endpoint-url https://storage.googleapis.com cp -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 2m33.148s, 200.59 MB/s
# n2-standard-80: 2m48.071s, 182.78 MB/stime s5cmd --endpoint-url https://storage.googleapis.com cp s3://doit-speed-test-bucket/temp_30GB_file .
# n2-standard-4: 1m46.378s, 288.78 MB/s
# n2-standard-80: 2m1.116s, 253.64 MB/s
Quelle amélioration spectaculaire ! Malgré une certaine variabilité dans les temps de transfert, il semble qu'en laissant -c et -p à leurs valeurs par défaut, on atteigne la vitesse optimale. On n'atteint pas le débit maximal d'écriture de 350 Mo/s, mais les ~289 Mo/s obtenus sur une n2-standard-4 s'en rapprochent bien davantage que les ~64 Mo/s offerts par gsutil sur la même machine. Soit une multiplication par 4,5 du débit en download, simplement en changeant d'outil.
En résumé, pour Linux :
- Comme
s5cmdne peut pas activer le multipart upload avec GCS, il est préférable de continuer à utilisergsutilpour les uploads vers GCS, à condition d'inclure-o GSUtil:parallel_composite_upload_threshold=150M. - Avec ses paramètres par défaut,
s5cmdsurclasse largementgsutilen download. Le simple fait d'utiliser un outil écrit dans un langage compilé apporte une amélioration spectaculaire (×4,5).
Performances d'une VM Windows avec gsutil : gros fichiers
Si vous trouviez ce qui précède déjà inhabituel, accrochez-vous : on plonge dans Windows. Le client DoiT travaillant sur Windows Server, il était temps de benchmarker cet OS. J'ai commencé à soupçonner que le problème ne se situait pas entre la chaise et le clavier.
Ayant confirmé que, sous Linux, gsutil excelle en upload avec les bons paramètres et s5cmd en download avec ses paramètres par défaut, il était temps d'essayer ces commandes sous Windows — où mon manque d'expérience avec PowerShell allait à nouveau me rappeler à l'humilité.
J'ai fini par recueillir des benchmarks sur une machine n2-standard-4 équipée d'un SSD local et basée sur l'image GCE Windows Server version 1809 Datacenter Core for Containers, built on 20200813. Du fait des frais de licence par vCPU appliqués à Windows Server, j'ai choisi de ne pas mesurer les performances sur une n2-standard-80.
Une remarque importante avant de plonger dans les chiffres :
La documentation GCP sur le rattachement de SSD locaux recommande, pour tous les Windows Server, d'utiliser le pilote SCSI plutôt que le pilote NVMe utilisé habituellement sous Linux, le SCSI étant mieux optimisé pour atteindre le débit maximal. J'ai donc provisionné deux VM avec un SSD local rattaché : l'une via NVMe, l'autre via SCSI, afin de comparer leurs performances avec les outils et paramètres déjà examinés.
Voici les benchmarks d'upload :
Measure-Command {gsutil cp temp_30GB_file gs://doit-speed-test-bucket/}
# NVMe: 3m50.064s, 133.53 MB/s
# SCSI: 4m7.256s, 124.24 MB/sMeasure-Command {gsutil -m cp temp_30GB_file gs://doit-speed-test-bucket/}
# NVMe: 3m59.462s, 128.29 MB/s
# SCSI: 3m34.013s, 143.54 MB/sMeasure-Command {gsutil -o GSUtil:parallel_composite_upload_threshold=150M cp temp_30GB_file gs://doit-speed-test-bucket/}
# NVMe: 5m54.046s, 86.77 MB/s
# SCSI: 6m13.929s, 82.15 MB/sMeasure-Command {gsutil -m -o GSUtil:parallel_composite_upload_threshold=150M cp temp_30GB_file gs://doit-speed-test-bucket/}
# NVMe: 5m55.751s, 86.40 MB/s
# SCSI: 5m58.078s, 85.79 MB/s

Les mots me manquent…
Sans aucun argument fourni à gsutil, le débit en upload n'atteint que 60 % de celui obtenu sur une machine Linux. Toute combinaison d'arguments dégrade les performances. Lorsqu'on active le multipart upload — qui apportait un gain de 42 % sous Linux —, le débit chute de 35 %. Vous remarquerez aussi que sans -m, alors que gsutil peut s'optimiser pour un fichier unique volumineux, l'upload depuis le disque NVMe se termine plus rapidement que depuis le disque SCSI — ce dernier étant censé bénéficier de pilotes mieux optimisés pour Windows Server. Que se passe-t-il ?!
Un débit en upload faible, autour de 80–85 Mo/s, correspondait exactement à la plage que rencontrait le client DoiT : son problème était au moins reproductible. En supprimant l'argument recommandé par GCP
-o GSUtil:parallel_composite_upload_threshold=150M pour les uploads de gros fichiers, le client pouvait éliminer une pénalité de 35 % sur les performances. 🤷
Les benchmarks de download racontent une histoire encore plus déconcertante :
Measure-Command {gsutil cp gs://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 11m39.426s, 43.92 MB/s
# NVMe 2nd attempt: 9m1.857s, 56.69 MB/s
# SCSI 1st attempt: 8m54.462s, 57.48 MB/s
# SCSI 2nd attempt: 10m1.023s, 51.05 MB/sMeasure-Command {gsutil -m cp gs://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 8m52.537s, 57.69 MB/s
# NVMe 2nd attempt: 22m4.824s, 23.19 MB/s
# NVMe 3rd attempt: 8m50.202s, 57.94 MB/s
# SCSI 1st attempt: 7m29.502s, 68.34 MB/s
# SCSI 2nd attempt: 9m9.652s, 55.89 MB/s
Impossible d'obtenir des benchmarks de download cohérents en raison du problème suivant :
- Chaque opération de download restait bloquée jusqu'à 2 minutes avant de démarrer
- Le téléchargement débutait et progressait à environ 68–70 Mo/s, jusqu'à ce que…
- Il s'interrompe parfois à nouveau pour une durée indéterminée
Ce cycle de blocage et de redémarrage se répétait, faisant osciller la moyenne du débit pour une même VM et un même disque entre 23 et 58 Mo/s. Difficile, dans ces conditions, de déterminer si NVMe ou SCSI est plus optimal pour les downloads. Nous y reviendrons.
Performances d'une VM Windows avec s5cmd : gros fichiers
Frustré par les performances erratiques de gsutil en download, je suis rapidement passé à s5cmd — peut-être atténuerait-il l'impact des blocages ?
Commençons par les benchmarks d'upload avec s5cmd :
Measure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 temp_30GB_file s3://doit-speed-test-bucket/}
# NVMe: 6m21.780s, 80.46 MB/s
# SCSI: 7m14.162s, 70.76 MB/sMeasure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp -p=1000000 temp_30GB_file s3://doit-speed-test-bucket/}
# NVMe: 12m56.066s, 39.58 MB/s
# SCSI: 8m12.255s, 62.41 MB/s
Comme pour s5cmd sous Linux, l'outil est handicapé par l'impossibilité d'utiliser le multipart upload. Avec une concurrence de 1, les performances en upload sont comparables à celles obtenues sous Linux, mais avec la valeur par défaut de 5, on observe des chutes (et des écarts) de débit spectaculaires. L'effet de la concurrence est inhabituellement marqué, mais comme s5cmd reste nettement moins performant que gsutil en upload (étrange, d'ailleurs, puisque c'est aussi vrai quand aucun des deux n'utilise le multipart), on n'utilisera pas s5cmd pour les uploads de toute façon. Passons donc sur cette singularité.
Voyons maintenant les benchmarks de download avec s5cmd :
Measure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 2m17.954s, 222.68 MB/s
# NVMe 2nd attempt: 1m44.718s, 293.36 MB/s
# SCSI 1st attempt: 3m9.581s, 162.04 MB/s
# SCSI 2nd attempt: 1m52.500s, 273.07 MB/sMeasure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 s3://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 3m18.006s, 155.15 MB/s
# NVMe 2nd attempt: 4m2.792s, 126.53 MB/s
# SCSI 1st attempt: 3m37.126s, 141.48 MB/s
# SCSI 2nd attempt: 4m9.657s, 123.05 MB/sMeasure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 2m17.151s, 223.99 MB/s
# NVMe 2nd attempt: 1m47.217s, 286.52 MB/s
# SCSI 1st attempt: 4m39.120s, 110.06 MB/s
# SCSI 2nd attempt: 1m42.159s, 300.71 MB/sMeasure-Command {s5cmd --endpoint-url https://storage.googleapis.com cp s3://doit-speed-test-bucket/temp_30GB_file .}
# NVMe 1st attempt: 2m48.714s, 182.08 MB/s
# NVMe 2nd attempt: 2m41.174s, 190.60 MB/s
# SCSI 1st attempt: 2m35.480s, 197.58 MB/s
# SCSI 2nd attempt: 2m40.483s, 191.42 MB/s
Même s'il subsiste des blocages et de la variabilité comme avec gsutil, s5cmd reste largement plus performant en download. Les blocages y sont également moins fréquents et/ou plus courts. Ils restent toutefois un problème occasionnel.
Contrairement à Linux où l'on atteignait les performances maximales en omettant -c et -p, sous Windows il semble que les performances optimales soient obtenues en incluant les deux avec -c=1 -p=1000000. Difficile d'affirmer catégoriquement que c'est la configuration la plus optimale compte tenu des blocages aléatoires, mais elle fonctionne suffisamment bien. Comme avec gsutil, ces blocages compliquent aussi la comparaison entre NVMe et SCSI.
Pour mieux comprendre les vitesses de download sur NVMe et SCSI avec les arguments s5cmd optimaux, j'ai écrit une fonction qui rapporte les durées Moy., Min. et Max. sur 20 téléchargements répétés, afin de lisser les blocages momentanés :
Measure-CommandAvg {s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .}
### With 20 sample downloads
# NVMe:
# Avg: 1m48.014s, 284.41 MB/s
# Min: 1m23.411s, 368.30 MB/s
# Max: 3m10.989s, 160.85 MB/s
# SCSI:
# Avg: 1m47.737s, 285.14 MB/s
# Min: 1m24.784s, 362.33 MB/s
# Max: 4m44.807s, 107.86 MB/s
La variabilité dans la durée d'un même download persiste, mais il apparaît clairement que SCSI n'offre globalement aucun avantage sur NVMe pour les téléchargements de gros fichiers, malgré son statut de pilote prétendument idéal pour un SSD local sur une VM Windows.
Vérifions également si les uploads sont plus performants via NVMe avec la même fonction de moyennage sur 20 uploads répétés :
Measure-CommandAvg {gsutil cp temp_30GB_file gs://doit-speed-test-bucket/}
# NVMe:
# Avg: 3m23.216s, 151.17 MB/s
# Min: 2m31.169s, 203.22 MB/s
# Max: 4m13.943s, 121.42 MB/s
# SCSI:
# Avg: 5m1.570s, 101.87 MB/s
# Min: 3m2.649s, 168.19 MB/s
# Max: 35m3.276s, 14.61 MB/s
Cela confirme nos premiers résultats individuels suggérant que NVMe peut être plus performant que SCSI pour les uploads. Sur cette série de vingt échantillons, NVMe est nettement plus rapide.
Ainsi, sur les VM Windows, et contrairement à la documentation GCP, non seulement il faut éviter d'utiliser -o GSUtil:parallel_composite_upload_threshold=150M avec gsutil pour uploader vers GCS, mais il faut aussi éviter SCSI et privilégier NVMe comme pilote du SSD local pour améliorer les uploads — et peut-être les downloads. On observe également que les uploads comme les downloads subissent des pauses fréquentes et imprévisibles allant de 1 à 2 minutes, voire de 10 à 30 minutes.
Que dire au client…
À ce stade, j'ai informé le client qu'il existait des limitations de transfert intrinsèques à l'utilisation d'une VM Windows, mais qu'elles pouvaient être partiellement atténuées en :
- Laissant les arguments optionnels à leurs valeurs par défaut pour les uploads de gros fichiers avec
gsutil cp, contrairement aux recommandations de la documentation GCP - Utilisant
s5cmd -c=1 -p=1000000au lieu degsutilpour les downloads - Utilisant le pilote NVMe plutôt que SCSI pour le SSD local, afin d'améliorer les uploads et possiblement les downloads, contrairement aux recommandations de la documentation GCP
J'ai toutefois aussi indiqué au client que les uploads et downloads seraient bien plus rapides en évitant tout simplement les blocages liés à Windows : transférer les données vers une machine Linux via des snapshots de disque, puis effectuer les opérations de synchronisation avec GCS depuis un disque rattaché à Linux. C'est finalement la méthode la plus rapide pour atteindre le débit attendu entre une VM GCE et GCS, et le client est reparti satisfait — quoique frustré par les problèmes de performance absurdes de son Windows Server.
Ce que je retiens de cette expérience : non seulement gsutil est cruellement sous-optimisé pour les opérations sur Windows Server, mais il semble également exister un problème sous-jacent dans la capacité de GCS à transférer des données vers et depuis Windows, des délais et blocages affectant à la fois gsutil et s5cmd en download comme en upload.
Le problème du client était résolu… mais ma curiosité, elle, ne l'était pas. Quelles autres surprises pourraient surgir si je tentais de transférer un grand nombre de petits fichiers plutôt qu'un petit nombre de gros fichiers ?
Performances d'une VM Linux avec gsutil : petits fichiers
Retour sous Linux : j'ai découpé le gros fichier de 30 Go en 50 000 (en réalité 50 001) fichiers :
mkdir parts
split -b 644245 temp_30GB_file
mv x* parts/
Puis j'ai procédé au benchmark des performances d'upload avec gsutil :
nohup bash -c 'time gsutil cp -r parts/* gs://doit-speed-test-bucket/smallparts/' &
# n2-standard-4: 71m30.420s, 7.16 MB/s
# n2-standard-80: 69m32.803s, 7.36 MB/snohup bash -c 'time gsutil -m cp -r parts/* gs://doit-speed-test-bucket/smallparts/' &
# n2-standard-4: 9m7.045s, 56.16 MB/s
# n2-standard-80: 3m41.081s, 138.95 MB/s
Comme prévu, fournir -m pour activer l'upload parallèle multi-thread améliore considérablement la vitesse — n'essayez jamais d'uploader un grand dossier de fichiers sans cette option. Plus la machine dispose de vCPU, plus elle peut gérer d'uploads simultanés.
Voici les benchmarks de download avec gsutil :
nohup bash -c 'time gsutil cp -r gs://doit-speed-test-bucket/smallparts/ parts/' &
# n2-standard-4: 61m24.516s, 8.34 MB/s
# n2-standard-80: 56m54.841s, 9.00 MB/snohup bash -c 'time gsutil -m cp -r gs://doit-speed-test-bucket/smallparts/ parts/' &
# n2-standard-4: 7m42.249s, 66.46 MB/s
# n2-standard-80: 3m38.421s, 140.65 MB/s
Là encore, -m est indispensable — n'essayez pas de télécharger un grand dossier de fichiers sans. Comme pour les uploads, les performances de gsutil profitent du transfert parallèle de fichiers via -m et de la disponibilité de nombreux vCPU.
Rien d'anormal donc sous Linux avec gsutil pour le transfert massif de petits fichiers.
Performances d'une VM Linux avec s5cmd : petits fichiers
Comme nous avons déjà établi que s5cmd ne devait pas servir aux uploads vers GCS, je ne présente que les benchmarks de download sous Linux :
nohup bash -c 'time s5cmd --endpoint-url https://storage.googleapis.com cp s3://doit-speed-test-bucket/smallparts/* parts/' &
# n2-standard-4: 1m19.531s, 386.26 MB/s
# n2-standard-80: 1m31.592s, 335.40 MB/snohup bash -c 'time s5cmd --endpoint-url https://storage.googleapis.com cp -c=80 s3://doit-speed-test-bucket/smallparts/* parts/' &
# n2-standard-80: 1m29.837s, 341.95 MB/s
Sur la n2-standard-4, on observe une accélération de 6,9× pour le téléchargement massif de petits fichiers comparé à gsutil. Il est donc judicieux d'utiliser s5cmd aussi bien pour télécharger un grand nombre de petits fichiers que des fichiers plus volumineux.
Aucun comportement anormal n'a été observé sous Linux pour les downloads massifs de petits fichiers via s5cmd.
Performances d'une VM Windows avec s5cmd : petits fichiers (et tests supplémentaires sur gros fichiers)
s5cmd étant nettement plus rapide que gsutil en download quel que soit l'OS, je n'examinerai que s5cmd pour les benchmarks de download Windows sur petits fichiers :
Measure-CommandAvg {s5cmd --endpoint-url https://storage.googleapis.com cp s3://doit-speed-test-bucket/smallparts/* parts/}
# NVMe:
# Avg: 2m39.540s, 192.55 MB/s
# Min: 2m35.323s, 197.78 MB/s
# Max: 2m44.260s, 187.02 MB/s
# SCSI:
# Avg: 2m45.431s, 185.70 MB/s
# Min: 2m40.785s, 191.06 MB/s
# Max: 2m50.930s, 179.72 MB/s
Le téléchargement de 50 000 petits fichiers vers une VM Windows s'avère plus performant et plus prévisible que celui de fichiers beaucoup plus volumineux. NVMe ne devance SCSI que d'un cheveu.
On constate une régularité étonnante et une absence de blocages prolongés dans ce cas d'usage, à l'inverse des commandes individuelles sur gros fichiers vues précédemment. Pour confirmer que les blocages affectent surtout les gros fichiers, j'ai exécuté la fonction de moyennage sur 20 téléchargements répétés du fichier de 30 Go :
Measure-CommandAvg {s5cmd --endpoint-url https://storage.googleapis.com cp -p=1000000 s3://doit-speed-test-bucket/temp_30GB_file .}
### With 20 sample downloads
# NVMe:
# Avg: 3m3.770s, 167.17 MB/s
# Min: 1m34.901s, 323.70 MB/s
# Max: 10m34.575s, 48.41 MB/s
# SCSI:
# Avg: 2m20.131s, 219.22 MB/s
# Min: 1m31.585s, 335.43 MB/s
# Max: 3m43.215s, 137.63 MB/s
Sur Windows, la durée de download via NVMe oscille entre 1 min 37 s et 10 min 35 s, alors qu'avec 50 000 petits fichiers sur le même OS, elle se situe entre 2 min 35 s et 2 min 44 s. Il existe donc bien un problème spécifique à Windows ou à GCS pour les transferts de gros fichiers sur une VM Windows.
Notez également que la durée moyenne de download sur NVMe semble environ 73 % plus longue (3 min 3 s contre 1 min 46 s) que lors de l'exécution de s5cmd sous Linux.
Il serait tentant d'affirmer que SCSI est plus avantageux que NVMe pour les téléchargements massifs de petits fichiers d'après les résultats ci-dessus, mais les blocages aléatoires faussent la moyenne. Je continuerai à recommander NVMe, étant donné son efficacité prouvée pour les uploads massifs de petits fichiers (voir ci-dessous) et ses performances comparables à SCSI pour les téléchargements de gros fichiers.
Performances d'une VM Windows avec gsutil : petits fichiers
Voici les mesures pour l'upload massif de petits fichiers depuis une VM Windows :
Measure-CommandAvg {gsutil -q -m cp -r parts gs://doit-speed-test-bucket/smallparts/}
# NVMe:
# Avg: 16m36.562s, 30.83 MB/s
# Min: 16m22.914s, 31.25 MB/s
# Max: 17m0.299s, 30.11 MB/s
# SCSI:
# Avg: 17m29.591s, 29.27 MB/s
# Min: 17m5.236s, 29.96 MB/s
# Max: 18m3.469s, 28.35 MB/s
NVMe surpasse SCSI, et les vitesses restent bien inférieures à celles d'une machine Linux. Sous Linux, l'upload massif de petits fichiers prend environ 9 min 7 s, ce qui rend la moyenne Windows NVMe de 16 min 36 s environ 82 % plus lente que Linux.
Reproductibilité des benchmarks
Si vous souhaitez reproduire mes résultats avec vos propres benchmarks, voici les scripts shell et PowerShell utilisés, accompagnés de commentaires synthétisant les débits observés :
Conclusions sur l'utilisation efficace des outils de transfert
En définitive, déterminer la meilleure méthode pour transférer des données entre des VM GCE — avec données stockées sur SSD local — et GCS s'avère bien plus complexe qu'il ne le devrait.

Les écarts de performance entre les différents OS GCE et GCS sont liés d'une manière ou d'une autre, j'en suis convaincu
Les Windows Server subissent des chutes drastiques de débit en download comme en upload, pour des raisons encore inconnues, par rapport aux meilleures commandes équivalentes sous Linux. Ces baisses de performance sont importantes, généralement 70 à 80 % en deçà du meilleur équivalent Linux. Les transferts de gros fichiers sont plus durement touchés que ceux de nombreux petits fichiers.
Ainsi, si vous devez migrer plusieurs To de données ou des fichiers particulièrement volumineux depuis Windows vers GCS dans un délai contraint, mieux vaut contourner ces problèmes de performance : prenez un snapshot du disque, rattachez un disque créé à partir de ce snapshot à une machine Linux, puis effectuez l'upload depuis cet OS.
Indépendamment des problèmes liés à Windows Server, l'outil de transfert par défaut gsutil disponible sur les VM GCE est inadéquat pour les downloads à haut débit, quel que soit l'OS. En utilisant s5cmd à la place, vous pouvez multiplier la vitesse de download par plusieurs.
Pour vous aider à vous y retrouver dans la multitude d'outils et d'arguments, voici un récapitulatif de mes recommandations pour maximiser le débit, basé sur les benchmarks de cet article :
Linux — Download
- Un seul gros fichier :
s5cmd --endpoint-url https://storage.googleapis.com cp s3://your_bucket/your_file . - Plusieurs fichiers, petits ou gros :
s5cmd --endpoint-url https://storage.googleapis.com cp s3://your_bucket/path* your_path/
Linux — Upload
- Un seul gros fichier :
gsutil -o GSUtil:parallel_composite_upload_threshold=150M cp your_file gs://your_bucket/ - Plusieurs fichiers, petits ou gros :
gsutil -m -o GSUtil:parallel_composite_upload_threshold=150M cp -r your_path/ gs://your_bucket/
Windows Server — Download
- Utilisez NVMe, pas SCSI, pour rattacher un SSD local
- Un seul gros fichier :
s5cmd --endpoint-url https://storage.googleapis.com cp -c=1 -p=1000000 s3://your_bucket/your_file . - Plusieurs fichiers, petits ou gros :
s5cmd --endpoint-url https://storage.googleapis.com cp s3://your_bucket/path* your_path/
Windows Server — Upload
- Utilisez NVMe, pas SCSI, pour rattacher un SSD local
- Un seul gros fichier :
gsutil cp your_file gs://your_bucket/ - Plusieurs fichiers, petits ou gros :
gsutil -m cp -r your_path/ gs://your_bucket/your_path/