106 votes

Est-il possible d'effectuer un téléchargement en lot vers Amazon S3 ?

Est-ce qu'Amazon S3 prend en charge les téléversements en lot? J'ai un travail qui doit téléverser chaque nuit environ 100 000 fichiers qui peuvent aller jusqu'à 1 Go, mais qui sont fortement déséquilibrés en faveur de petits fichiers (90% font moins de 100 octets et 99% font moins de 1000 octets de longueur).

Est-ce que l'API S3 prend en charge le téléversement de plusieurs objets en un seul appel HTTP?

Tous les objets doivent être disponibles dans S3 en tant qu'objets individuels. Je ne peux pas les héberger ailleurs (FTP, etc.) ou dans un autre format (base de données, lecteur local EC2, etc.). C'est une exigence externe que je ne peux pas modifier.

54voto

RubyFanatic Points 808

Alternativement, vous pouvez télécharger S3 via l'outil AWS CLI en utilisant la commande sync.

aws s3 sync dossier_local s3://nom-du-bucket

Vous pouvez utiliser cette méthode pour télécharger en lot des fichiers vers S3 très rapidement.

45voto

Ryan Weir Points 2960

Est-ce que l'API S3 prend en charge le téléchargement de plusieurs objets en un seul appel HTTP?

Non, l'opération PUT de S3 prend en charge uniquement le téléchargement d'un objet par requête HTTP.

Vous pouvez installer S3 Tools sur votre machine que vous voulez synchroniser avec le bucket distant, et exécuter la commande suivante:

s3cmd sync localdirectory s3://bucket/

Ensuite, vous pourriez placer cette commande dans un script et créer une tâche planifiée pour exécuter cette commande chaque nuit.

Cela devrait répondre à vos besoins.

L'outil effectue la synchronisation des fichiers en fonction des hachages MD5 et de la taille du fichier, donc les collisions devraient être rares (si vous le souhaitez vraiment, vous pourriez simplement utiliser la commande "s3cmd put" pour forcer l'écrasement aveugle des objets dans votre bucket cible).

EDIT: Assurez-vous également de lire la documentation sur le site que j'ai lié pour S3 Tools - il existe différents indicateurs nécessaires pour savoir si vous souhaitez que les fichiers supprimés localement soient également supprimés du bucket ou ignorés, etc.

13voto

saaj Points 412

Enquête

Est-il possible d'effectuer un téléchargement par lots vers Amazon S3 ?

Oui*.

Est-ce que l'API S3 prend en charge le téléchargement de plusieurs objets en un seul appel HTTP ?

Non.

Explication

L'API Amazon S3 ne prend pas en charge le téléchargement en masse, mais awscli prend en charge le téléchargement simultané (parallèle). Du point de vue du client et de l'efficacité de la bande passante, ces options devraient fonctionner de manière similaire.

 ────────────────────── temps ────────────────────►

    1. Série
 ------------------
   POST /ressource
 ────────────────► POST /ressource
   donnée_1      └───────────────► POST /ressource
                   données_2     └───────────────►
                                   données_3
    2. En bloc
 ------------------
   POST /en-bloc
 ┌────────────┐
 │ressources :│
 │- données_1 │
 │- données_2 ├──►
 │- données_3 │
 └────────────┘

    3. Concurrent
 ------------------
   POST /ressource
 ────────────────►
   données_1

   POST /ressource
 ────────────────►
   données_2

   POST /ressource
 ────────────────►
   données_3

Interface en ligne de commande AWS

La documentation sur comment améliorer les performances de transfert de la commande de synchronisation pour Amazon S3 suggère d'augmenter la concurrence de deux manières. L'une d'elles est la suivante :

Pour améliorer les performances éventuelles, vous pouvez modifier la valeur de max_concurrent_requests. Cette valeur définit le nombre de requêtes pouvant être envoyées vers Amazon S3 en même temps. La valeur par défaut est de 10, et vous pouvez l'augmenter à une valeur plus élevée. Cependant, notez ce qui suit :

  • Lancer davantage de threads consomme plus de ressources sur votre machine. Vous devez vous assurer que votre machine dispose de suffisamment de ressources pour prendre en charge le nombre maximal de requêtes simultanées que vous souhaitez.
  • Trop de requêtes simultanées peuvent submerger un système, ce qui pourrait entraîner des délais de connexion ou ralentir la réactivité du système. Pour éviter les problèmes de délai d'attente à partir de l'AWS CLI, vous pouvez essayer de définir la valeur de --cli-read-timeout ou la valeur de --cli-connect-timeout à 0.

Un script définissant max_concurrent_requests et téléchargeant un répertoire peut ressembler à ceci :

aws configure set s3.max_concurrent_requests 64
aws s3 cp chemin_local_de s3://chemin_distant_vers --récursif

Pour avoir une idée du fait que lancer plus de threads consomme plus de ressources, j'ai fait une petite mesure dans un conteneur exécutant aws-cli (en utilisant procpath) en téléchargeant un répertoire avec environ 550 fichiers HTML (environ 40 Mio au total, taille moyenne du fichier d'environ 72 Kio) vers S3. Le graphique suivant montre l'utilisation du processeur, le RSS et le nombre de threads du processus de téléchargement aws.

aws s3 cp --récursif, max_concurrent_requests=64

3voto

Samuel Dominguez Points 153

Pour ajouter à ce que tout le monde dit, si vous voulez que votre code Java (au lieu de l'interface en ligne de commande) fasse cela sans avoir à mettre tous les fichiers dans un seul répertoire, vous pouvez créer une liste de fichiers à téléverser et ensuite fournir cette liste à la méthode uploadFileList de TransferManager d'AWS.

https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/transfer/TransferManager.html#uploadFileList-java.lang.String-java.lang.String-java.io.File-java.util.List-

2voto

Max Points 461

Voici une solution batch complète qui copie des fichiers d'un dossier à un autre en utilisant un seul appel de CommandPool::batch, bien que sous-jacent il exécute une commande executeAsync pour chaque fichier, donc je ne suis pas sûr que cela compte comme un seul appel API.

D'après ce que je comprends, vous devriez être capable de copier des centaines de milliers de fichiers en utilisant cette méthode car il n'y a pas de moyen d'envoyer un lot à AWS pour qu'il soit traité là-bas, mais si vous hébergez ceci sur une instance AWS ou même si vous l'exécutez sur Lambda, alors c'est "techniquement" traité chez AWS.

Installez le SDK :

composer require aws/aws-sdk-php

use Aws\ResultInterface;
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
use Aws\S3\Exception\DeleteMultipleObjectsException;

$bucket = 'nom-de-mon-bucket';

// Configurez vos identifiants dans le dossier .aws
// Voir : https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials_profiles.html
$s3 = new S3Client([
    'profile' => 'default',
    'region'  => 'us-east-2',
    'version' => 'latest'
]);

// Obtenez tous les fichiers dans S3
$files = array();
try {
    $results = $s3->getPaginator('ListObjects', [
        'Bucket' => $bucket,
        'Prefix' => 'dossier-existant' // Dossier dans le bucket, ou supprimez ceci pour obtenir tous les fichiers dans le bucket
    ]);

    foreach ($results as $result) {
        foreach ($result['Contents'] as $object) {
            $files[] = $object['Key'];
        }
    }
} catch (AwsException $e) {
    error_log($e->getMessage());
}

if(count($files) > 0){
    // Effectuer un lot d'opérations de Copie d'objet.
    $batch = [];
    foreach ($files as $file) {
        $batch[] = $s3->getCommand('CopyObject', array(
            'Bucket'     => $bucket,
            'Key'        => str_replace('dossier-existant/', 'nouveau-dossier/', $file),
            'CopySource' => $bucket . '/' . $file,
        ));
    }

    try {
        $results = CommandPool::batch($s3, $batch);

        // Vérifiez si tous les fichiers ont été copiés afin de supprimer en toute sécurité l'ancien répertoire
        $count = 0;
        foreach($results as $result) {
            if ($result instanceof ResultInterface) {
                $count++;
            }
            if ($result instanceof AwsException) {
            }
        }

        if($count === count($files)){
            // Supprimer l'ancien répertoire
            try {
                $s3->deleteMatchingObjects(
                    $bucket, // Bucket
                    'dossier-existant' // Préfixe, dossier dans le bucket, comme indiqué ci-dessus
                );
            } catch (DeleteMultipleObjectsException $exception) {
                return false;
            }

            return true;
        }

        return false;

    } catch (AwsException $e) {
        return $e->getMessage();
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X