CosmosDb велика частота запросов с insertMany - PullRequest
0 голосов
/ 20 марта 2019

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

public bool InsertZonierData(List<Zonier> zonierList)
{
    if (zonierList == null || !zonierList.Any())
    {
        throw new ZonierListNullOrEmptyException();
    }
    else
    {
        try
        {
            _collection.InsertMany(zonierList);
            return true;
        }
        catch (MongoBulkWriteException ex)
        {
            throw new DataBaseWritingException(ex.Message, ExceptionCodeConstants.DataBaseWritingExceptionCode);
        }
    }
}

К сожалению, имея более 30000 элементов в zonierList, он создает следующее исключение для CosmosDb:

Необработанное исключение: MongoDB.Driver.MongoCommandException: Ошибка вставки команды: Сообщение: {"Ошибки": ["Частота запросов велика"]}

Следуя документации, это проблема, связанная с RU / sec в Космосе. Конечно, простым способом было бы увеличить его, но я не хочу этого делать.

Существует ли простой и понятный способ реорганизовать метод, позволяющий нам вставлять данные без отрыва 400 RU / сек от CosmosDb.

Ответы [ 3 ]

1 голос
/ 06 июля 2019

Драйвер Mongo сообщает, какие записи получили ошибки, а какие не были обработаны вообще. Если все ошибки (обычно одна) имеют код 16500, значит, проблема заключается в регулировании и повторении ошибок, а оставшиеся записи безопасны. В противном случае ваши ошибки вызваны чем-то другим, и вам следует провести анализ и решить, следует ли продолжать повторные попытки.

Драйвер Mongo не возвращает HTTP-заголовок, где Cosmos DB предлагает задержку перед повторной попыткой, но это не имеет большого значения. Задержка не гарантирует успеха в любом случае, потому что другие запросы, попадающие в ту же базу данных, могут использовать RU. Вам лучше экспериментировать и определять свои собственные правила повтора. Ниже приведено простое рекурсивное решение, которое повторяет попытки до тех пор, пока все не будет исправлено или не достигнут предел повторения.

    private async Task InsertManyWithRetry(IMongoCollection<BsonDocument> collection, 
        IEnumerable<BsonDocument> batch, int retries = 10, int delay = 300)
    {
        var batchArray = batch.ToArray();

        try
        {
            await collection.InsertManyAsync(batchArray);
        }
        catch (MongoBulkWriteException<BsonDocument> e)
        {
            if (retries <= 0)
                throw;

            //Check if there were any errors other than throttling.
            var realErrors = e.WriteErrors.Where(we => we.Code != 16500).ToArray();
            //Re-throw original exception for now.
            //TODO: We can make it more sophisticated by continuing with unprocessed records and collecting all errors from all retries.
            if (realErrors.Any())
                throw;

            //Take all records that had errors.
            var errors = e.WriteErrors.Select(we => batchArray[we.Index]);
            //Take all unprocessed records.
            var unprocessed = e.UnprocessedRequests
                .Where(ur => ur.ModelType == WriteModelType.InsertOne)
                .OfType<InsertOneModel<BsonDocument>>() 
                .Select(ur => ur.Document);

            var retryBatchArray = errors.Union(unprocessed).ToArray();

            _logger($"Retry {retryBatchArray.Length} records after {delay} ms");

            await Task.Delay(delay);

            await InsertManyWithRetry(collection, retryBatchArray, retries - 1, delay);
        }
    }
1 голос
/ 20 марта 2019

Mongo SDK совершенно не знает о существовании CosmosDB. Это означает, что у него нет логики повторения для дросселированных запросов. Это означает, что, если вы хотите, чтобы количество RU составляло 400, вам придется пакетировать свой список и вызывать метод insertmany, используя механизм регулирования на стороне клиента.

Вы можете рассчитать это, получив размер каждого документа, умножив его на 10, что составляет плату за вставку 1 КБ документа, а затем напишите фрагмент кода, который объединяет документы на основе размера и выполняется один раз в секунду.

0 голосов
/ 12 июня 2019

Я решил это с помощью логики повторов для космоса с помощью Mongo API.Вы можете применить задержку в соответствии с вашими требованиями.

public void Insert(List<BsonDocument> list)
    {
        try
        {
            var collection = this.db.GetCollection<BsonDocument>(COLLECTION_NAME);
            collection.InsertMany(list);
        } catch (MongoBulkWriteException ex)
        {
            int index = ex.WriteErrors[0].Index;
            Insert(list.GetRange(index, list.Count - index));
        }

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...