Медленная производительность на Azure DocumentDB

В настоящее время я сталкиваюсь с довольно медленным временем отклика от Azure DocumentDB (впервые попробовал).

В коллекции есть 31 объект, который я собираюсь извлечь и вернуть вызывающему. Код, который я использую, следующий:

public async Task<List<dynamic>> Get(string collectionName = null)
{
    // Lookup from Dictionary, takes literally no time
    var collection = await GetCollectionAsync(collectionName);

    var sw = Stopwatch.StartNew();

    var query = await
        _client.CreateDocumentQuery(collection.DocumentsLink, 
            new FeedOptions { MaxItemCount = 1000 })
            .AsDocumentQuery()
            .ExecuteNextAsync();

    Trace.WriteLine($"Get documents: {sw.ElapsedMilliseconds} ms");

    return query.ToList();
}

Чтобы создать экземпляр клиента, я использую следующий код:

_client = new DocumentClient(new Uri(endpoint), authKey, new ConnectionPolicy
{
    ConnectionMode = ConnectionMode.Direct,
    ConnectionProtocol = Protocol.Tcp
});

Время отклика, которое я получаю от Stopwatch, составляет от 360 мс до 1200 мс, чтобы вернуть 31 объект. Для меня это довольно медленно. Без пользовательского ConnectionPolicy среднее время отклика составляет около 950 мс.

Я делаю что-то неправильно здесь? Возможно ли как-то ускорить эти запросы?

Вот результат из Trace, распечатав прошедшее время секундомера:

Get documents: 1984 ms
Get documents: 1252 ms
Get documents: 1246 ms
Get documents: 359 ms
Get documents: 356 ms
Get documents: 356 ms
Get documents: 351 ms
Get documents: 1248 ms
Get documents: 1314 ms
Get documents: 1250 ms

Ответы

Ответ 1

Обновлен, чтобы отражать последние изменения службы (1/22/2017): DocumentDB гарантирует латентность чтения p99 < 10 мс и латентность записи p99 < 15 мс с SLA на стороне базы данных. Нижеприведенные советы по-прежнему применяются для обеспечения чтения с низкой задержкой с использованием SDK **

Обновлено с учетом последних изменений службы (6/14/2016): Не нужно кэшировать собственные ссылки при использовании маршрутизации через определяемые пользователем идентификаторы. Также добавлено еще несколько советов. **

Чтение обычно занимает < 1 мс на самом сегменте хранения DocumentDB; и узким местом часто является латентность сети между приложением и базой данных. Таким образом, лучше всего, чтобы приложение работало в том же центре данных, что и база данных.

Вот несколько общих советов по использованию SDK:

Совет # 1: используйте однодисковый клиент DocumentDB для срока службы вашего приложения

Обратите внимание, что каждый экземпляр DocumentClient является потокобезопасным и обеспечивает эффективное управление соединениями и кэширование адресов при работе в прямом режиме. Чтобы обеспечить эффективное управление соединениями и лучшую производительность с помощью DocumentClient, рекомендуется использовать один экземпляр DocumentClient для каждого приложения в течение всего жизненного цикла приложения.

Совет # 2: документ и коллекция кэша SelfLinks для более низкой латентности чтения

В Azure DocumentDB каждый документ имеет сгенерированный системой selfLink. Эти SelfLinks гарантированно будут уникальными и неизменными для срока службы документа. Чтение одного документа с использованием selfLink является наиболее эффективным способом получения единого документа. Из-за неизменности selfLink вы должны кэшировать selfLinks, когда это возможно, для лучшей производительности чтения.

Document document = await client.ReadDocumentAsync("/dbs/1234/colls/1234354/docs/2332435465");

Сказав это, приложение может не всегда работать с документами selfLink для чтения сценариев; в этом случае следующим наиболее эффективным способом получения документа является запрос по предоставленному пользователем объекту Id. Например:

IDocumentQuery<Document> query = (from doc in client.CreateDocumentQuery(colSelfLink) where doc.Id == "myId" select document).AsDocumentQuery(); 
            Document myDocument = null;
            while (query.HasMoreResults)
            {
                FeedResponse<Document> res = await query.ExecuteNextAsync<Document>();
                if (res.Count != 0) {
                    myDocument = res.Single();
                    break;
                }
           }

Совет № 3: Настройте размер страницы для запросов/каналов чтения для лучшей производительности

При выполнении массового чтения документов с использованием функции чтения фида (т.е. ReadDocumentFeedAsync) или при выпуске SQL-запроса DocumentDB результаты возвращаются сегментированным образом, если набор результатов слишком велик. По умолчанию результаты возвращаются в кусках из 100 элементов или 1 МБ, в зависимости от того, какой предел был достигнут первым.

Чтобы уменьшить количество сетевых обходов, необходимых для получения всех применимых результатов, вы можете увеличить размер страницы, используя заголовок запроса x-ms-max-item-count до 1000. В тех случаях, когда вам нужно отображать только несколько результатов, например, если ваш пользовательский интерфейс или API-интерфейс API возвращает только десять результатов за раз, вы также можете уменьшить размер страницы до 10, чтобы уменьшить пропускную способность, потребляемую для чтения и запросов.

Вы также можете установить размер страницы, используя доступные SDK DocumentDB. Например:

IQueryable<dynamic> authorResults =
client.CreateDocumentQuery(documentCollection.SelfLink, "SELECT p.Author FROM Pages p WHERE p.Title = 'About Seattle'", new FeedOptions { MaxItemCount = 1000 });

Еще несколько советов (6/14/2016):

  • Используйте точки чтения (например, прочитайте документ вместо документа запроса) для поиска по id
  • Настроить клиент DocumentDB (используя ConnectionPolicy) для использования прямого подключения через шлюз.
  • Выделите клиентов в том же Azure Region, что и ваша база данных.
  • Вызов OpenAsync(), чтобы предотвратить более высокую задержку первого вызова.
  • Вы можете отлаживать запросы LINQ, вызывая ToString() в запросе, чтобы увидеть запрос SQL, отправленный по проводу

Для получения дополнительных рекомендаций по производительности ознакомьтесь с этим сообщением .