【问题标题】:Why does golang concurrent uploading of files to S3 bucket result in canceled, context deadline exceeded为什么golang并发文件上传到S3桶会导致取消,超出上下文截止日期
【发布时间】:2022-08-04 16:12:34
【问题描述】:

我写了一小段golang代码,递归遍历一个目录,上传director中的文件。目录中大约有 93K+ 项。 过了一会儿,我收到以下错误:

上传文件时出错:/Users/randolphhill/Fat-Tree-Business/SandBox/DDD/heydoc/ios/Pods/gRPC-Core/src/core/ext/transport/chttp2/alpn/alpn.h 操作错误 S3:PutObject,https 响应错误 StatusCode:0,RequestID:,HostID:,已取消,超出上下文期限。

下面是代码sn-p

   func PutFile(c context.Context, api S3PutObjectAPI, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
        return api.PutObject(c, input)
}

func PutFileS3(dir, filename, bucket, reg string) error {
        var cfg aws.Config
        st, err := fthash.Filehash(dir + filename)
        if err != nil {
                panic(\"configuration error, \" + err.Error())
                return err
        }
        m := make(map[string]string)
        m[\"hashcode\"] = st
        cfg, err = config.LoadDefaultConfig(context.TODO(), config.WithRegion(reg))
        if err != nil {
                panic(\"configuration error, \" + err.Error())
        }

        client := s3.NewFromConfig(cfg)
        tmp := \"backup\" + dir + filename
        uri := strings.Replace(tmp, \" \", \"##,##\", -1)
        if checkFileOnS3(client, bucket, uri, st) {
                fmt.Println(\" FILE EXIST\")
                return nil

        }
        file, err2 := os.Open(dir + filename)
        defer file.Close()

        if err2 != nil {
                fmt.Println(\"Unable to open file \" + filename)
                return err2
        }

        tmp = \"backup\" + dir + filename
        //uri := \"backup\" + dir + filename
        uri = strings.Replace(tmp, \" \", \"##,##\", -1)
        input := &s3.PutObjectInput{
                Bucket: &bucket,
                Key:    aws.String(uri),
                //Key:    &filename,
                Body:     file,
                Metadata: m,
        }
        ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
        defer cancelFn()
        _, err2 = PutFile(ctx, client, input)
        if err2 != nil {
                fmt.Println(\"Got error uploading file:\", dir+filename)
                fmt.Println(err2)
                return err2
        }

        return nil
}
  • 您是否有任何可能需要超过 10 秒才能上传的较大文件?
  • 超时与上下文创建有关,与收到的最新字节无关。 Iirc 有第三方软件包可以解决缺少实际传输超时的问题。
  • 这只是一个实验。我认为拥有大量 goroutine(数千个)是一个沉重的负担。不确定在哪一端。该程序基于 OSX 12.1 构建。我将在 Ubuntu 上进行测试,看看是否得到相同的结果
  • 你可以运行几千个 goroutine 没问题,如果它们正在等待网络 I/O,它们真的没有开销。但是 S3 只会让你发出这么多的并发请求 - 它很多,但不是无限的。您的操作系统可能也为您的用户配置了默认的ulimit 1024,除非您已更改它。

标签: go amazon-s3


【解决方案1】:

您在此处添加了 10 秒超时:

        ctx, cancelFn := context.WithTimeout(context.TODO(), 10*time.Second)
        defer cancelFn()
        _, err2 = PutFile(ctx, client, input)
        if err2 != nil {
                fmt.Println("Got error uploading file:", dir+filename)
                fmt.Println(err2)
                return err2
        }

10 秒后,对PutFile 的调用将退出并出现上下文错误。如果您的文件上传时间较长,您可能只需要增加超时时间。

【讨论】:

  • 我添加的时间显着增加。我想我会在 Ubuntu 上进行测试,看看是否得到相同的结果。如果结果相同,我会将应用程序更改为生产者-消费者实现。
【解决方案2】:
package main

import (
    // "html/template"
    "log"
    "net/http"
    "os"

    "github.com/gin-gonic/gin"
    "github.com/joho/godotenv"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var AccessKeyID string
var SecretAccessKey string
var MyRegion string
var MyBucket string
var filepath string

//GetEnvWithKey : get env value
func GetEnvWithKey(key string) string {
    return os.Getenv(key)
}

func LoadEnv() {
    err := godotenv.Load(".env")
    if err != nil {
        log.Fatalf("Error loading .env file")
        os.Exit(1)
    }
}

func ConnectAws() *session.Session {
    AccessKeyID = GetEnvWithKey("AWS_ACCESS_KEY_ID")
    SecretAccessKey = GetEnvWithKey("AWS_SECRET_ACCESS_KEY")
    MyRegion = GetEnvWithKey("AWS_REGION")

    sess, err := session.NewSession(
        &aws.Config{
            Region: aws.String(MyRegion),
            Credentials: credentials.NewStaticCredentials(
                AccessKeyID,
                SecretAccessKey,
                "", // a token will be created when the session it's used.
            ),
        })

    if err != nil {
        panic(err)
    }

    return sess
}

func SetupRouter(sess *session.Session) {
    router := gin.Default()

    router.Use(func(c *gin.Context) {
        c.Set("sess", sess)
        c.Next()
    })

    // router.Get("/upload", Form)
    router.POST("/upload", UploadImage)
    // router.GET("/image", controllers.DisplayImage)

    _ = router.Run(":4000")
}

func UploadImage(c *gin.Context) {
    sess := c.MustGet("sess").(*session.Session)
    uploader := s3manager.NewUploader(sess)

    MyBucket = GetEnvWithKey("BUCKET_NAME")

    file, header, err := c.Request.FormFile("photo")
    filename := header.Filename

    //upload to the s3 bucket
    up, err := uploader.Upload(&s3manager.UploadInput{
        Bucket: aws.String(MyBucket),
        //ACL:    aws.String("public-read"),
        Key:  aws.String(filename),
        Body: file,
    })

    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error":    "Failed to upload file",
            "uploader": up,
        })
        return
    }
    filepath = "https://" + MyBucket + "." + "s3-" + MyRegion + ".amazonaws.com/" + filename
    c.JSON(http.StatusOK, gin.H{
        "filepath": filepath,
    })
}

func main() {
    LoadEnv()

    sess := ConnectAws()
    router := gin.Default()
    router.Use(func(c *gin.Context) {
        c.Set("sess", sess)
        c.Next()
    })

    router.POST("/upload", UploadImage)

    //router.LoadHTMLGlob("templates/*")
    //router.GET("/image", func(c *gin.Context) {
    //c.HTML(http.StatusOK, "index.tmpl", gin.H{
    //  "title": "Main website",
    //})
    //})

    _ = router.Run(":4000")
}

【讨论】:

  • 使用 API 将文件上传到 aws s3 。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-08
  • 2022-07-11
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多