Оптимизация производительности в Azure Cosmos DB: лучшие практики и советы

Когда мы работаем с базой данных, оптимизация имеет решающее значение для производительности и эффективности приложения. Точно так же в Azure Cosmos DB оптимизация важна для максимизации эффективности, минимизации затрат и обеспечения эффективного масштабирования вашего приложения. Ниже представлены некоторые из лучших практик с примерами кода для оптимизации производительности в Azure Cosmos DB.

1. Выбор правильного ключа раздела

Выбор подходящего ключа раздела имеет решающее значение для распределенных баз данных, таких как Cosmos DB. Хороший ключ раздела обеспечивает равномерное распределение данных по разделам, уменьшая горячие точки и улучшая производительность.

Выбор ключа раздела прост, но очень важен на этапе проектирования в Azure Cosmos DB. После того как мы выберем ключ раздела, изменить его на месте будет невозможно.

Лучшие практики

  • Выберите ключ раздела с высокой кардинальностью (много уникальных значений).
  • Убедитесь, что он равномерно распределяет чтения и записи.
  • Сохраняйте связанные данные вместе, чтобы минимизировать межразделковые запросы.

Пример: Создание контейнера с оптимальным ключом раздела

C#

 

var database = await cosmosClient.CreateDatabaseIfNotExistsAsync("YourDatabase");
var containerProperties = new ContainerProperties
{
    Id = "myContainer",
    PartitionKeyPath = "/customerId"  // Partition key selected to ensure balanced distribution
}; 

// Создать контейнер с провизией 400 RU/s
var container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

2. Правильное Использование индексации

В Azure Cosmos DB индексы применяются ко всем свойствам по умолчанию, что может быть полезно, но может привести к увеличению затрат на хранение и RU/s. Для улучшения производительности запросов и минимизации расходов рассмотрите настройку политики индексации. Cosmos DB поддерживает три типа индексов: Диапазонные индексы, Пространственные индексы и Композитные индексы. Используйте правильный тип с умом.

Лучшая практика

  • Исключите избыточные поля из индексации.
  • Используйте композитные индексы для запросов с несколькими полями.

Пример: Настройка пользовательской политики индексации

C#

 

{
    "indexingPolicy": {
        "automatic": true,
        "indexingMode": "consistent",  // Can use 'none' or 'lazy' to reduce write costs
        "includedPaths": [
            {
                "path": "/orderDate/?",  // Only index specific fields like orderDate
                "indexes": [
                    {
                        "kind": "Range",
                        "dataType": "Number"
                    }
                ]
            }
        ],
        "excludedPaths": [
            {
                "path": "/largeDataField/*"  // Exclude large fields not used in queries
            }
        ]
    }
}

Пример: Добавление композитного индекса для оптимизированных запросов

C#

 

{
    "indexingPolicy": {
        "compositeIndexes": [
            [
                { "path": "/lastName", "order": "ascending" },
                { "path": "/firstName", "order": "ascending" }
            ]
        ]
    }
}

Вы можете узнать больше о типах индексации здесь.

3. Оптимизация запросов

Эффективный поиск является ключевым для минимизации единиц запросов (RU/s) и улучшения производительности в Azure Cosmos DB. Стоимость RU/s зависит от сложности запроса и его размера.

Использование пакетных исполнителей дополнительно снизит затраты за счет уменьшения потребляемых RU на операцию. Эта оптимизация поможет эффективно управлять использованием RU и снизить общие расходы на Cosmos DB.

Лучшие практики

  • Используйте запросы SELECT в ограниченном количестве, извлекайте только необходимые свойства.
  • Избегайте запросов между разделами, указывая ключ раздела в вашем запросе.
  • Используйте фильтры на индексированных полях для снижения затрат на запросы.

Пример: Получение записи о клиенте

C#

 

var query = new QueryDefinition("SELECT c.firstName, c.lastName FROM Customers c WHERE c.customerId = @customerId")
    .WithParameter("@customerId", "12345");

var iterator = container.GetItemQueryIterator<Customer>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")  // Provide partition key to avoid cross-partition query
});

while (iterator.HasMoreResults)
{
    var response = await iterator.ReadNextAsync();
    foreach (var customer in response)
    {
        Console.WriteLine($"{customer.firstName} {customer.lastName}");
    }
}

4. Настройка уровней согласованности

Уровни согласованности определяют конкретные операционные режимы, предназначенные для обеспечения гарантий, связанных со скоростью. В Cosmos DB доступно пять уровней согласованности (Strong, Bounded Staleness, Session, Consistent Prefix и Eventual). Каждый уровень согласованности влияет на задержку, доступность и пропускную способность.

Лучшие практики

  • Используйте согласованность сессий для большинства сценариев для балансировки производительности и согласованности данных.
  • Сильная согласованность гарантирует согласованность данных, но увеличивает RU/s и задержку.

Пример: Установка уровня согласованности

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // Установите согласованность на "Сессия" для сбалансированной производительности
		ConsistencyLevel = ConsistencyLevel.Session      
});

Узнайте больше об уровне согласованности здесь.

5. Используйте выделенную пропускную способность (RU/s) и автомасштабирование разумно

Настройка пропускной способности является ключевым фактором для достижения оптимальной производительности и эффективного управления затратами в Azure Cosmos DB. Сервис позволяет настраивать пропускную способность двумя способами:

  • Фиксированные RU/s: Предопределенный постоянный уровень единиц запросов в секунду (RU/s), подходящий для рабочих нагрузок с постоянными требованиями к производительности.
  • Автомасштабирование: Динамический вариант, который автоматически корректирует пропускную способность в зависимости от колебаний нагрузки, обеспечивая масштабируемость и избегая избыточной настройки в периоды низкой активности.

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

Лучшие практики

  • Для предсказуемых рабочих нагрузок настраивайте пропускную способность вручную.
  • Используйте автомасштабирование для непредсказуемых или всплесковых рабочих нагрузок.

Пример: Настройка пропускной способности с Автомасштабированием

C#

 

var throughputProperties = ThroughputProperties.CreateAutoscaleThroughput(maxThroughput: 4000);  // Autoscale up to 4000 RU/s 
var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
	Id = "autoscaleContainer",
	PartitionKeyPath = "/userId"
}, throughputProperties);

Пример: Ручная установка фиксированных RU/s для стабильных рабочих нагрузок 

C#

 

var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
    Id = "manualThroughputContainer",
    PartitionKeyPath = "/departmentId"
}, throughput: 1000);  // Fixed 1000 RU/s

6. Используйте Change Feed для эффективной обработки данных в реальном времени

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

Лучшие практики

  • Используйте поток изменений для сценариев, где необходимо обрабатывать изменения данных в реальном времени (например, аналитика в реальном времени, уведомления, оповещения).

Пример: Чтение из потока изменений

C#

 

var iterator = container.GetChangeFeedIterator(
ChangeFeedStartFrom.Beginning(),
ChangeFeedMode.Incremental);
while (iterator.HasMoreResults)
{
    var changes = await iterator.ReadNextAsync();
    foreach (var change in changes)
    {
        Console.WriteLine($"Detected change: {change.Id}");
        // Обработайте изменение (например, вызов события, обновление кеша)
    }
}

7. Использование времени жизни (TTL) для автоматической истечения данных

Если у вас есть данные, которые актуальны только в течение ограниченного времени, такие как логи или данные сессий, включение времени жизни (TTL) в Azure Cosmos DB может помочь управлять затратами на хранение. TTL автоматически удаляет просроченные данные после указанного периода хранения, устраняя необходимость в ручной очистке данных. Этот подход не только снижает объем хранимых данных, но и обеспечивает оптимизацию вашей базы данных для экономии затрат, удаляя устаревшую или ненужную информацию.

Лучшие практики

  • Установите TTL для контейнеров, где данные должны автоматически истекать, чтобы сократить расходы на хранение.

Пример: Установка времени жизни (TTL) для данных с истечением срока действия

C#

 

{
    "id": "sessionDataContainer",
    "partitionKey": { "paths": ["/sessionId"] },
    "defaultTtl": 3600  // 1 hour (3600 seconds)
}

В Cosmos DB, максимальное значение времени жизни (TTL), которое можно установить, составляет 365 дней (1 год). Это означает, что данные могут быть автоматически удалены после истечения срока годности в течение года с момента создания или последней модификации, в зависимости от настроек TTL.

8. Избегайте запросов между разделами

Запросы между разделами могут значительно увеличить RU/s и задержку. Чтобы избежать этого:

Лучшие практики

  • Всегда включайте ключ раздела в ваши запросы.
  • Разработайте стратегию разделения, чтобы минимизировать доступ между разделами.

Пример: Запрос с использованием ключа раздела для избежания запроса между разделами

C#

 

var query = new QueryDefinition("SELECT * FROM Orders o WHERE o.customerId = @customerId")
    .WithParameter("@customerId", "12345"); 

var resultSetIterator = container.GetItemQueryIterator<Order>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")
});

while (resultSetIterator.HasMoreResults)
{
    var response = await resultSetIterator.ReadNextAsync();
    foreach (var order in response)
    {
        Console.WriteLine($"Order ID: {order.Id}");
    }
}

Вывод

Эти советы очень эффективны во время разработки. С помощью эффективной стратегии разделения, настройки политик индексирования, оптимизации запросов, настройки уровней согласованности и выбора соответствующих моделей предоставления пропускной способности, вы можете значительно улучшить производительность и эффективность развертывания Azure Cosmos DB. Эти оптимизации не только улучшают масштабируемость, но также помогают в управлении затратами, обеспечивая высокопроизводительный опыт работы с базой данных.

Source:
https://dzone.com/articles/optimizing-performance-in-azure-cosmos-db