【问题标题】:DynamoDB takes too much time to respond for a single itemDynamoDB 对单个项目的响应时间过长
【发布时间】:2021-04-08 09:38:16
【问题描述】:

我有一个 Go REST 服务,它连接到 DynamoDB 以检索一些产品。该表有大约 100.000 个产品,我通常检索大约 20.0000 个(然后在实际回复之前被其他进程过滤掉,但这与我的问题无关)。

我看到的问题是我的整个请求大约需要 4 秒,这对我的目标来说非常高。我开始在我的应用程序中记录每一层,直到最终到达最小的部分,即从数据库中检索一个项目的每个单独的部分。

令我惊讶的是,每个项目检索大约需要 3.6 秒??!!。

不管下面的代码,这可能是什么原因?我在发电机的配置上缺少什么吗?

func (db DynamoRepository) FetchProducts(c *gin.Context, pID string) ([]models.Product, error) {
    output := make([]models.Product, 0)
    chProduct := make(chan *models.Product)

    sem := make(chan struct{}, 40000)
    wait := sync.WaitGroup{}
    wait.Add(1)
    go func (wg *sync.WaitGroup) {
        defer wg.Done()
        for i := 0; i < len(itemIDs); i++ {
            p := <-chProduct
            if p != nil {
                output = append(output, *p)
            }
        }
        close(chProduct)
    }(&wait)
    for index := range itemIDs {
        sem <- struct{}{}
        go func(ix int, s chan struct{}, ch chan *models.Product) {
            defer func() {
               <- s
            }()
            infoSlice := strings.Split(itemIDs[ix], "_")
            if len(infoSlice) != 2 {
                ch <- nil
                return
            }
            key := map[string]*dynamodb.AttributeValue{
                "PK": {
                    N: aws.String(pID),
                },
                "SK": {
                    S: aws.String("product"),
                },
            }
            start := time.Now()
            result, err := db.DB.GetByKey(c, db.Config.AWS.Table, key)
            fmt.Printf("Item %s took %d\n", productID, time.Since(start).Milliseconds())
            if err != nil {
                ch <- nil
                return
            }
            if result.Item == nil {
                ch <- nil
                return
            }
            var product models.Product
            err = dynamodbattribute.UnmarshalMap(result.Item, &product)
            if err != nil {
                ch <- nil
                return
            }
            ch <- &product
        }(index, sem, chProduct)
    }
    wait.Wait()

    if len(output) == 0 {
        return nil, nil
    }
    return output, nil
}

GetByKey的实现:

func (provider *DynamoDBProvider) GetByKey(ctx context.Context, tableName string, key map[string]*dynamodb.AttributeValue) (*dynamodb.GetItemOutput, error) {
    input := &dynamodb.GetItemInput{
        TableName: aws.String(tableName),
        Key:       key,
    }

    result, err := provider.client.GetItem(input)

    return result, err
} 

【问题讨论】:

  • 当使用其他客户端连接到您的DynamoDB实例时,时间上的差异有多大?这可能是网络延迟问题。此外,BatchGetItem 允许您一次获取多达 100 个对象,这比单独获取它们要快得多。
  • 嗨 Mikael,我最终会将实现更改为 BatchGetItem,但这个问题仍然会大大减慢进程。
  • 对于其他客户端,其他 Go 项目使用相同的 SDK,并且对他们来说工作正常
  • 您的容量是按需还是预配?
  • 您的后台吞吐量是多少?如果您的读取次数从 0 次增加到 20,000 次,DynamoDB 不太可能立即扩展吞吐量。如果您重复测试(即预热数据库),您的响应时间会缩短吗?

标签: go amazon-dynamodb


【解决方案1】:

这就是我最终做的,它极大地改善了延迟。我按照本指南创建了一个自定义 HTTP 客户端:

https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/custom-http.html

延迟从近 4 秒变为 500 毫秒~。为什么?我不知道,但它有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-24
    • 2016-07-20
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 2021-08-21
    相关资源
    最近更新 更多