

 **Cette page est réservée aux clients existants du service Amazon Glacier utilisant Vaults et l'API REST d'origine datant de 2012.**

Si vous recherchez des solutions de stockage d'archives, nous vous recommandons d'utiliser les classes de stockage Amazon Glacier dans Amazon S3, S3 Glacier Instant Retrieval, S3 Glacier Flexible Retrieval et S3 Glacier Deep Archive. Pour en savoir plus sur ces options de stockage, consultez les [classes de stockage Amazon Glacier](https://aws.amazon.com/s3/storage-classes/glacier/).

Amazon Glacier (service autonome d'origine basé sur un coffre-fort) n'accepte plus de nouveaux clients. Amazon Glacier est un service autonome doté de son propre service APIs qui stocke les données dans des coffres-forts et qui se distingue des classes de stockage Amazon S3 et Amazon S3 Glacier. Vos données existantes resteront sécurisées et accessibles indéfiniment dans Amazon Glacier. Aucune migration n'est requise. Pour un stockage d'archivage à long terme et à faible coût AWS , nous [recommandons les classes de stockage Amazon S3 Glacier](https://aws.amazon.com/s3/storage-classes/glacier/), qui offrent une expérience client supérieure avec des compartiments S3, une Région AWS disponibilité totale APIs, des coûts réduits et AWS une intégration des services. Si vous souhaitez des fonctionnalités améliorées, envisagez de migrer vers les classes de stockage Amazon S3 Glacier en suivant nos [conseils relatifs aux AWS solutions pour le transfert de données depuis les coffres-forts Amazon Glacier vers les classes de stockage Amazon S3 Glacier](https://aws.amazon.com/solutions/guidance/data-transfer-from-amazon-s3-glacier-vaults-to-amazon-s3/).

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Téléchargement d'une archive volumineuse à l'aide du traitement parallèle avec Python
<a name="downloading-large-archive-parallel-python"></a>

Cette rubrique explique comment télécharger une archive volumineuse depuis Amazon S3 Glacier (S3 Glacier) à l'aide du traitement parallèle avec Python. Cette approche vous permet de télécharger de manière fiable des archives de toutes tailles en les divisant en petits morceaux pouvant être traités indépendamment.

## Présentation de
<a name="downloading-large-archive-python-overview"></a>

Le script Python fourni dans cet exemple exécute les tâches suivantes :

1. Configure les AWS ressources nécessaires (rubrique Amazon SNS et files d'attente Amazon SQS) pour les notifications

1. Lance une tâche de récupération d'archives avec Amazon Glacier

1. Surveille une file d'attente Amazon SQS pour détecter les notifications de fin de tâche

1. Divise la grande archive en morceaux faciles à gérer

1. Télécharge des segments en parallèle à l'aide de plusieurs threads de travail

1. Enregistre chaque morceau sur le disque pour un réassemblage ultérieur

## Conditions préalables
<a name="downloading-large-archive-python-prerequisites"></a>

Avant de commencer, assurez-vous d'avoir :
+ Python 3.6 ou version ultérieure installé
+ AWS SDK pour Python (Boto3) installé
+ AWS informations d'identification configurées avec les autorisations appropriées pour Amazon Glacier, Amazon SNS et Amazon SQS
+ Espace disque suffisant pour stocker les fragments d'archive téléchargés

## Exemple : téléchargement d'une archive à l'aide du traitement parallèle avec Python
<a name="downloading-large-archive-python-code"></a>

Le script Python suivant montre comment télécharger une archive volumineuse depuis Amazon Glacier à l'aide du traitement parallèle :

```
import boto3
import time
import json
import jmespath
import re
import concurrent.futures
import os

output_file_path = "output_directory_path"
vault_name = "vault_name"

chunk_size = 1000000000 #1gb - size of chunks for parallel download.
notify_queue_name = 'GlacierJobCompleteNotifyQueue' # SQS queue for Glacier recall notification
chunk_download_queue_name='GlacierChunkReadyNotifyQueue' # SQS queue for chunks
sns_topic_name = 'GlacierRecallJobCompleted' # the SNS topic to be notified when Glacier archive is restored.
chunk_queue_visibility_timeout = 7200 # 2 hours - this may need to be adjusted.
region = 'us-east-1'
archive_id = "archive_id_to_restore"
retrieve_archive = True # set to false if you do not want to restore from Glacier - useful for restarting or parallel processing of the chunk queue.
workers = 12 # the number of parallel worker threads for downloading chunks. 

def setup_queues_and_topic():
    sqs = boto3.client('sqs')
    sns = boto3.client('sns')

    # Create the SNS topic
    topic_response = sns.create_topic(
        Name=sns_topic_name
    )
    topic_arn = topic_response['TopicArn']
    print("Creating the SNS topic " + topic_arn)

    # Create the notification queue
    notify_queue_response = sqs.create_queue(
        QueueName=notify_queue_name,
        Attributes={
            'VisibilityTimeout': '300',  # 5 minutes
            'ReceiveMessageWaitTimeSeconds': '20'  # Enable long polling
        }
    )
    notify_queue_url = notify_queue_response['QueueUrl']
    print("Creating the archive-retrieval notification queue " + notify_queue_url)

    # Create the chunk download queue
    chunk_queue_response = sqs.create_queue(
        QueueName=chunk_download_queue_name,
        Attributes={
            'VisibilityTimeout': str(chunk_queue_visibility_timeout),  # 5 minutes
            'ReceiveMessageWaitTimeSeconds': '0'
        }
    )
    chunk_queue_url = chunk_queue_response['QueueUrl']

    print("Creating the chunk ready notification queue " + chunk_queue_url)


   # Get the ARN for the notification queue
    notify_queue_attributes = sqs.get_queue_attributes(
        QueueUrl=notify_queue_url,
        AttributeNames=['QueueArn']
    )
    notify_queue_arn = notify_queue_attributes['Attributes']['QueueArn']

    # Set up the SNS topic policy on the notification queue
    queue_policy = {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
            "Sid": "allow-sns-messages",
            "Effect": "Allow",
            "Principal": {"AWS": "*"},
            "Action": "SQS:SendMessage",
            "Resource": notify_queue_arn,
            "Condition": {
                "ArnEquals": {
                    "aws:SourceArn": topic_arn
                }
            }
        }]
    }

    # Set the queue policy
    sqs.set_queue_attributes(
        QueueUrl=notify_queue_url,
        Attributes={
            'Policy': json.dumps(queue_policy)
        }
    )

    # Subscribe the notification queue to the SNS topic
    sns.subscribe(
        TopicArn=topic_arn,
        Protocol='sqs',
        Endpoint=notify_queue_arn
    )

    return {
        'topic_arn': topic_arn,
        'notify_queue_url': notify_queue_url,
        'chunk_queue_url': chunk_queue_url
    }


def split_and_send_chunks(archive_size, job_id,chunk_queue_url):
    ranges = []
    current = 0
    chunk_number = 0

    while current < archive_size:
        chunk_number += 1
        next_range = min(current + chunk_size - 1, archive_size - 1)
        ranges.append((current, next_range, chunk_number))
        current = next_range + 1

    # Send messages to SQS queue
    for start, end, chunk_number in ranges:
        body = {"start": start, "end": end, "job_id": job_id, "chunk_number": chunk_number}
        body = json.dumps(body)
        print("Sending SQS message for range:" + str(body))
        response = sqs.send_message(
            QueueUrl=chunk_queue_url,
            MessageBody=str(body)
        )

def GetJobOutputChunks(job_id, byterange, chunk_number):
    glacier = boto3.client('glacier')
    response = glacier.get_job_output(
        vaultName=vault_name,
        jobId=job_id,
        range=byterange,

    )

    with open(os.path.join(output_file_path,str(chunk_number)+".chunk"), 'wb') as output_file:
        output_file.write(response['body'].read())

    return response

def ReceiveArchiveReadyMessages(notify_queue_url,chunk_queue_url):

    response = sqs.receive_message(
        QueueUrl=notify_queue_url,
        AttributeNames=['All'],
        MaxNumberOfMessages=1,
        WaitTimeSeconds=20,
        MessageAttributeNames=['Message']
    )
    print("Polling archive retrieval job ready queue...")
    # Checking that there is a Messages key before proceeding. No 'Messages' key likely means the queue is empty

    if 'Messages' in response:
        print("Received a message from the archive retrieval job queue")
        jsonresponse = response
        # Loading the string into JSON and checking that ArchiveSizeInBytes key is present before continuing.
        jsonresponse=json.loads(jsonresponse['Messages'][0]['Body'])
        jsonresponse=json.loads(jsonresponse['Message'])
        if 'ArchiveSizeInBytes' in jsonresponse:
            receipt_handle = response['Messages'][0]['ReceiptHandle']    
            if jsonresponse['ArchiveSizeInBytes']:
                archive_size = jsonresponse['ArchiveSizeInBytes']

                print(f'Received message: {response}')      
                if archive_size > chunk_size:
                    split_and_send_chunks(archive_size, jsonresponse['JobId'],chunk_queue_url)

                    sqs.delete_message(
                    QueueUrl=notify_queue_url,
                    ReceiptHandle=receipt_handle)

            else:
                print("No ArchiveSizeInBytes value found in message")
                print(response)

    else:
        print('No messages available in the queue at this time.')

    time.sleep(1)

def ReceiveArchiveChunkMessages(chunk_queue_url):
    response = sqs.receive_message(
        QueueUrl=chunk_queue_url,
        AttributeNames=['All'],
        MaxNumberOfMessages=1,
        WaitTimeSeconds=0,
        MessageAttributeNames=['Message']
    )
    print("Polling archive chunk queue...")
    print(response)
    # Checking that there is a Messages key before proceeding. No 'Messages' key likely means the queue is empty
    if 'Messages' in response:
        jsonresponse = response
        # Loading the string into JSON and checking that ArchiveSizeInBytes key is present before continuing.
        jsonresponse=json.loads(jsonresponse['Messages'][0]['Body'])
        if 'job_id' in jsonresponse: #checking that there is a job id before continuing
            job_id = jsonresponse['job_id']
            byterange = "bytes="+str(jsonresponse['start']) + '-' + str(jsonresponse['end'])
            chunk_number = jsonresponse['chunk_number']
            receipt_handle = response['Messages'][0]['ReceiptHandle']
            if jsonresponse['job_id']:
                print(f'Received message: {response}')
                GetJobOutputChunks(job_id,byterange,chunk_number)
                sqs.delete_message(
                QueueUrl=chunk_queue_url,
                ReceiptHandle=receipt_handle)
    else:
        print('No messages available in the chunk queue at this time.')

def initiate_archive_retrieval(archive_id, topic_arn):
    glacier = boto3.client('glacier')

    job_parameters = {
        "Type": "archive-retrieval",
        "ArchiveId": archive_id,
        "Description": "Archive retrieval job",
        "SNSTopic": topic_arn,
        "Tier": "Bulk"  # You can change this to "Standard" or "Expedited" based on your needs
    }

    try:
        response = glacier.initiate_job(
            vaultName=vault_name,
            jobParameters=job_parameters
        )

        print("Archive retrieval job initiated:")
        print(f"Job ID: {response['jobId']}")
        print(f"Job parameters: {job_parameters}")
        print(f"Complete response: {json.dumps(response, indent=2)}")

        return response['jobId']

    except Exception as e:
        print(f"Error initiating archive retrieval job: {str(e)}")
        raise

def run_async_tasks(chunk_queue_url, workers):
    max_workers = workers  # Set the desired maximum number of concurrent tasks
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        for _ in range(max_workers):
            executor.submit(ReceiveArchiveChunkMessages, chunk_queue_url)

# One time setup of the necessary queues and topics. 
queue_and_topic_atts = setup_queues_and_topic()

topic_arn = queue_and_topic_atts['topic_arn']
notify_queue_url = queue_and_topic_atts['notify_queue_url']
chunk_queue_url = queue_and_topic_atts['chunk_queue_url']

if retrieve_archive:
    print("Retrieving the defined archive... The topic arn we will notify when recalling the archive is: "+topic_arn)
    job_id = initiate_archive_retrieval(archive_id, topic_arn)
else:
    print("Retrieve archive is false, polling queues and downloading only.")

while True:
   ReceiveArchiveReadyMessages(notify_queue_url,chunk_queue_url)
   run_async_tasks(chunk_queue_url,workers)
```

## Utilisation du script
<a name="downloading-large-archive-python-usage"></a>

Pour utiliser ce script, procédez comme suit :

1. Remplacez les valeurs d'espace réservé dans le script par vos informations spécifiques :
   + *output\$1file\$1path*: répertoire dans lequel les fichiers partiels seront enregistrés
   + *vault\$1name*: nom de votre coffre-fort S3 Glacier
   + *notify\$1queue\$1name*: nom de la file d'attente de notifications de tâches
   + *chunk\$1download\$1queue\$1name*: nom de la file d'attente de téléchargement des tronçons
   + *sns\$1topic\$1name*: nom de la rubrique SNS
   + *region*: AWS région dans laquelle se trouve votre coffre-fort
   + *archive\$1id*: ID de l'archive à récupérer

1. Exécutez le script  :

   ```
   python download_large_archive.py
   ```

1. Une fois tous les fragments téléchargés, vous pouvez les combiner dans un seul fichier à l'aide d'une commande telle que :

   ```
   cat /path/to/chunks/*.chunk > complete_archive.file
   ```

## Importantes considérations
<a name="downloading-large-archive-python-considerations"></a>

Lorsque vous utilisez ce script, tenez compte des points suivants :
+ L'extraction des archives depuis S3 Glacier peut prendre plusieurs heures, selon le niveau de récupération sélectionné.
+ Le script s'exécute indéfiniment, interrogeant continuellement les files d'attente. Vous souhaiterez peut-être ajouter une condition de résiliation en fonction de vos besoins spécifiques.
+ Assurez-vous de disposer de suffisamment d'espace disque pour stocker tous les fragments de votre archive.
+ Si le script est interrompu, vous pouvez le redémarrer `retrieve_archive=False` pour continuer à télécharger des fragments sans lancer une nouvelle tâche de récupération.
+ Ajustez les *workers* paramètres *chunk\$1size* et en fonction de la bande passante de votre réseau et des ressources système.
+  AWS Les frais standard s'appliquent pour les extractions Amazon S3, Amazon SNS et l'utilisation d'Amazon SQS.