#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 мс ~. Почему? Я понятия не имею, но это сработало.