Azure CosmosDB: повышение производительности массовой вставки - PullRequest
1 голос
/ 05 августа 2020

Я использую Azure Cosmos DB SDK (3.0) для операций CRUD. Когда я пытаюсь вставить 8 000–10 000 записей одновременно, это занимает почти 3-4 минуты.

Вот мой код:

  public async Task<ResultDto> HandleAsync(EnableOrDisableSubscriptionCommand command, ILogger logger)
        {
            logger.Info("Started EnableOrDisableSubscriptionCommand ", nameof(EnableOrDisableSubscriptionCommand));
            
            if (command.UiNotifications.Any())
            {
                await AddSubscription(command, SubscriptionAction.UiNotification, command.UiNotifications);
                logger.Info("Added UI notification subscriptions");
            }
            if (command.EmailNotifications.Any())
            {
                await AddSubscription(command, SubscriptionAction.Email, command.EmailNotifications);
                logger.Info("Added Email notification subscriptions");
            }

            return new ResultDto { ResultType = ResultType.Success, Message = $"User {command.UserId} SubscriptionStatus" };
        }

        
        private async Task AddSubscription(EnableOrDisableSubscriptionCommand command, SubscriptionAction subscriptionAction, IList<int> notificationCategoryTypes)
        {
            foreach (var notificationCategory in notificationCategoryTypes)
            {
                var notificationTypes = Utility.GetNotificationTypes((NotificationCategoryType)notificationCategory);

                foreach (var notificationType in notificationTypes)
                {
                    foreach (var payerAccountSubscriptions in command.Subscriptions)
                    {
                        if (payerAccountSubscriptions.AccountNumbers?.Any() ?? false)
                        {
                            foreach (var accountNumber in payerAccountSubscriptions.AccountNumbers.Where(a => !string.IsNullOrEmpty(a)))
                            {
                                await _repository.Create(subscriptionAction, notificationType,
                                     payerAccountSubscriptions.ColCoId, payerAccountSubscriptions.PayerNumber, accountNumber, command.UserRole,
                                     command.UserId);
                            }
                        }
                        else
                        {
                            await _repository.Create(subscriptionAction, notificationType,
                                payerAccountSubscriptions.ColCoId, payerAccountSubscriptions.PayerNumber, null, command.UserRole,
                                command.UserId);

                        }
                    }
                }
            }
        }

Метод создания репозитория подписок:

 public async Task Create(SubscriptionAction subscriptionAction, NotificationType notificationType,
            int colCoId, string payerNumber, string accountNumber, UserRole userRole, string userId, string cardId = null)
        {
            var eventType = Utility.GetEventType(notificationType);

            var subscriptionBase = new Subscription
            {
                Id = Guid.NewGuid(),
                IsActive = true,
                Action = subscriptionAction,
                ActionDesc = subscriptionAction.ToString(),
                Version = (int)SubscriptionVersion.V2,
                NotificationType = notificationType,
                NotificationTypeDesc = notificationType.ToString(),
                EventType = eventType,
                EventTypeDesc = eventType.ToString(),
                ColCoId = colCoId,
                PayerNumber = payerNumber,
                AccountNumber = accountNumber,
                CardId = cardId,
                DistributionGroups = new List<string> { userRole.ToString() },
                DistributionUserIds = new List<string> { userId }
            };
            await CreateItemAsync(subscriptionBase);
        }

Generi c Репозиторий:

 public async Task<ItemResponse<T>> CreateItemAsync(T item)
        {
            return await _container.CreateItemAsync<T>(item);
        }

Из-за этой проблемы My Http Trigger Azure Функция, возвращающая System.OutOfMemoryException.

Как я могу улучшить это?

1 Ответ

3 голосов
/ 05 августа 2020

Вы можете улучшить это, установив AllowBulkExecution = true в клиенте и добавив каждую операцию вставки к выполняемой задаче.

Вы можете узнать больше и увидеть пример здесь

Изменить: (это слишком долго для добавления в качестве комментария). Необходимое количество RU / s зависит от ряда факторов, в том числе от того, насколько быстро вы хотите получить данные. Я бы измерил стоимость вставки одного из этих элементов, а затем разделил бы вашу подготовленную пропускную способность на сумму для вставки одного элемента. Результатом должно быть количество элементов, которые вы можете вставить в секунду (при условии, что вы больше ничего не делаете). Если у вас есть один элемент, который стоит 10 RU / с для вставки, и у вас подготовлено 3000 RU / s, вы можете принимать 300 элементов в секунду. Для всего 10 000 элементов / 300 в секунду = 33 секунды.

Итак, если это занимает 3-4 минуты, значит, с вашим кодом что-то не так. Я бы go вернулся и прочитал статью, которую я опубликовал выше, потому что я не вижу, чтобы вы реализовали предлагаемый нами шаблон, в частности, помещаете каждую операцию в объект List, а затем вызываете await Task.WhenAll(this.Tasks);

Еще одна проблема, которую я вижу, это вы не указываете ключ раздела в вызове InsertItemsAsyn c (). Это запишет все в один пустой раздел и в конечном итоге перестанет принимать любые новые записи, как только он достигнет размера 20 ГБ.

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