2017-04-24 41 views
4

我正试图将给定的数据流保存到S3兼容存储中。 大小在流结束前是未知的,可以从5MB到500GB不等。如何在S3中保存数据流? aws-sdk-go示例不工作?

我尝试了不同的可能性,但没有找到比自己实现分片更好的解决方案。我最好的猜测是将一个固定大小的缓冲区填充到我的流中,并将其写入S3。 有更好的解决方案吗?也许这对我来说是透明的,而不是将整个流写入内存?

的AWS-SDK-去自述有一个例子PROGRAMM从标准输入提取数据,并将其写入S3:https://github.com/aws/aws-sdk-go#using-the-go-sdk

当我尝试管道数据与管|我得到以下错误: failed to upload object, SerializationError: failed to compute request body size caused by: seek /dev/stdin: illegal seek 我做错了什么,或者是这个例子不能像我期望的那样工作?

我虽然尝试微型去,与PutObject()client.PutObjectStreaming()。 这是功能性的,但会消耗与要存储的数据一样多的内存。

  1. 有没有更好的解决方案?
  2. 是否有一个可以将任意数据传输到S3的小例子程序?

回答

4

您可以使用SDK的Uploader处理未知大小的上传操作,但你需要通过包装成一个io.Reader使os.Stdin“unseekable”。这是因为Uploader虽然只需要一个io.Reader作为输入主体,但它会检查输入主体是否也是Seeker,如果是,它会调用Seek。而且由于os.Stdin只是一个*os.File,它实现了Seeker接口,默认情况下,您会从PutObjectWithContext获得同样的错误。

Uploader还允许您以可配置大小的区块上传数据,并且还可以配置应同时上传这些区块的数量。

下面是链接示例的修改版本,剥离可保持不变的代码。

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 
} 

至于这是否是比minio-go更好的解决方案,我不知道,你要测试自己。

+0

非常感谢。无论我存储5GB或25GB的数据,我做了一些测试并获得了大约500MB的持续内存使用量。这远非完美,但可以接受。 :) – xxorde

+0

我很高兴我能帮上忙。您使用的是什么部件尺寸以及允许多少并发上传? – mkopriva

+0

我没有明确设置并发上传并使用您的20MB作为PartSize。我只是尝试256MB,它消耗约2.1 GB的内存。 PartSize = 5MB则消耗132MB。我开始在这里看到一个模式;) – xxorde