Как сохранить потоки данных в S3? Пример aws-sdk-go не работает?

Я пытаюсь сохранить данный поток данных в хранилище, совместимом с S3. Размер не известен до окончания потока и может варьироваться от 5 МБ до ~500 ГБ.

Я пробовал разные возможности, но не нашел лучшего решения, чем сам осколок. Мое лучшее предположение - сделать буфер фиксированного размера, заполнить его потоком и записать в S3. Есть ли лучшее решение? Может быть, способ, где это прозрачно для меня, без записи всего потока в память?

В файле reads aws-sdk-go есть пример программы, которая берет данные из stdin и записывает их в S3: https://github.com/aws/aws-sdk-go

Когда я пытаюсь передать данные с помощью канала | Я получаю следующую ошибку: failed to upload object, SerializationError: failed to compute request body size caused by: seek /dev/stdin: illegal seek Я делаю что-то не так или пример не работает так, как я ожидаю?

Я хотя и пробовал minio-go, с PutObject() или client.PutObjectStreaming (). Это функционально, но потребляет столько же памяти, сколько и данные для хранения.

  1. Есть ли лучшее решение?
  2. Есть ли небольшой пример программы, которая может передавать произвольные данные в S3?

1 ответ

Решение

Вы можете использовать загрузчик SDK для обработки загрузок неизвестного размера, но вам нужно будет сделать os.Stdin "невидим", завернув его в io.Reader, Это потому что 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 Я не знаю, вам придется проверить это самостоятельно.

Другие вопросы по тегам