DynamoDB требует слишком много времени для ответа на один элемент

#go #amazon-dynamodb

# #Вперед #amazon-dynamodb

Вопрос:

У меня есть служба Go REST, которая подключается к DynamoDB для извлечения некоторых продуктов. В таблице около 100 000 продуктов, и я обычно извлекаю около 20,0000 (которые затем фильтруются другими процессами до фактического ответа, но это не имеет отношения к моей проблеме).

Проблема, которую я вижу, заключается в том, что весь мой запрос занимает около 4 секунд, что очень много для моих целей. Я начал регистрировать каждый уровень в своем приложении, пока, наконец, не достиг наименьшей части, которая представляет собой каждое отдельное извлечение элемента из базы данных.

К моему удивлению, поиск каждого элемента занимает примерно 3,6 секунды ??!!.

Независимо от приведенного ниже кода, каковы могут быть причины этого? Чего-то не хватает в конфигурации для dynamo?

 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)
    }(amp;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 %dn", 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, amp;product)
            if err != nil {
                ch <- nil
                return
            }
            ch <- amp;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 := amp;dynamodb.GetItemInput{
        TableName: aws.String(tableName),
        Key:       key,
    }

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

    return result, err
} 
 

Комментарии:

1. Насколько велика разница во времени при использовании других клиентов для подключения к вашему экземпляру DynamoDB? Это может быть проблема с задержкой в сети. Кроме того, BatchGetItem позволяет вам получать до 100 объектов одновременно, это будет намного быстрее, чем получать их по отдельности.

2. Привет, Микаэль, я в конечном итоге изменю реализацию на BatchGetItem, но все же эта проблема слишком сильно замедлит процесс.

3. Что касается других клиентов, другие проекты Go используют тот же SDK, и он отлично работает для них

4. Ваша емкость доступна по требованию или подготовлена?

5. Какова ваша фоновая пропускная способность? Если вы переходите от 0 операций чтения к 20 000, DynamoDB вряд ли сможет мгновенно увеличить пропускную способность. Уменьшается ли ваше время ответа, если вы повторяете тест (т. Е. Прогреваете базу данных)?

Ответ №1:

Это то, что я в итоге сделал, и это значительно улучшило задержку. Я следовал этому руководству, чтобы создать пользовательский HTTP-клиент :

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

Задержка увеличилась с почти 4 секунд до 500 мс ~. Почему? Я понятия не имею, но это сработало.