2017-04-24 1 views
4

J'essaie de conserver un flux de données donné dans un stockage compatible S3. La taille n'est pas connue avant la fin du flux et peut varier de 5 Mo à ~ 500 Go.Comment enregistrer des flux de données dans S3? aws-sdk-go exemple ne fonctionne pas?

J'ai essayé différentes possibilités mais je n'ai pas trouvé de meilleure solution que d'implémenter moi-même le sharding. Ma meilleure estimation est de faire un tampon d'une taille fixe le remplir avec mon flux et l'écrire sur le S3. Y a-t-il une meilleure solution? Peut-être un moyen où cela est transparent pour moi, sans écrire le flux entier à la mémoire?

Aws-sdk-go readme a un programm exemple qui utilise les données de stdin et écrit à S3: https://github.com/aws/aws-sdk-go#using-the-go-sdk

Lorsque je tente de données de conduite avec un tuyau | je reçois l'erreur suivante: failed to upload object, SerializationError: failed to compute request body size caused by: seek /dev/stdin: illegal seek Est-ce que je fais quelque chose de mal ou l'exemple ne fonctionne-t-il pas comme je le souhaite?

J'ai bien essayé minio-go, avec PutObject() ou client.PutObjectStreaming(). Ceci est fonctionnel mais consomme autant de mémoire que les données à stocker.

  1. Y a-t-il une meilleure solution?
  2. Existe-t-il un petit exemple de programme qui peut canaliser des données arbitraires dans S3?

Répondre

4

Vous pouvez utiliser pour gérer le téléchargement de taille inconnue Uploader de la sdk, mais vous aurez besoin de faire le os.Stdin « unseekable » en l'enveloppant dans un io.Reader. C'est parce que le Uploader, alors qu'il nécessite seulement un io.Reader comme le corps d'entrée, sous le capot il fait une vérification pour voir si le corps d'entrée est également un Seeker et si c'est le cas, il appelle Seek dessus. Et puisque os.Stdin est juste un *os.File qui implémente l'interface Seeker, par défaut, vous obtiendriez la même erreur que vous avez obtenu de PutObjectWithContext. Le Uploader permet également de télécharger les données dans des blocs dont vous pouvez configurer la taille et vous pouvez également configurer le nombre de ces blocs qui doivent être téléchargés simultanément.

Voici une version modifiée de l'exemple lié, dépouillé du code qui peut rester inchangé.

package main 

import (
    // ... 
    "io" 
    "github.com/aws/aws-sdk-go/service/s3/s3manager" 
) 

type reader struct { 
    r io.Reader 
} 

func (r *reader) Read(p []byte) (int, error) { 
    return r.r.Read(p) 
} 

func main() { 
    // ... parse flags 

    sess := session.Must(session.NewSession()) 
    uploader := s3manager.NewUploader(sess, func(u *s3manager.Uploader) { 
     u.PartSize = 20 << 20 // 20MB 
     // ... more configuration 
    }) 

    // ... context stuff 

    _, err := uploader.UploadWithContext(ctx, &s3manager.UploadInput{ 
     Bucket: aws.String(bucket), 
     Key: aws.String(key), 
     Body: &reader{os.Stdin}, 
    }) 

    // ... handle error 
} 

Quant à savoir si cela est une meilleure solution que minio-go Je ne sais pas, vous devrez tester vous-même.

+0

Merci beaucoup. J'ai fait quelques tests et j'ai une consommation de mémoire constante de ~ 500 Mo, peu importe si je stocke 5 Go ou 25 Go de données. C'est loin d'être parfait, mais acceptable. :) – xxorde

+0

Je suis content que je puisse vous aider. Quelle taille de pièce utilisez-vous et combien de téléchargements simultanés autorisez-vous? – mkopriva

+0

Je n'ai pas défini explicitement les téléchargements simultanés et j'ai utilisé 20 Mo comme PartSize. Je viens d'essayer 256 Mo et il consomme ~ 2.1 Go de mémoire. Avec PartSize = 5 Mo, il consomme 132 Mo. Je commence à voir un modèle ici;) – xxorde