Как добиться хороших показателей импорта с помощью CRM Online 2015

Сценарий:

Создавайте или обновляйте записи в CRM из внешней базы данных в зависимости от того, существует ли ключ записи в CRM или нет.

Платформа: CRM 2015 Online.

Метод SSIS с компонентом .Net 4 Script

Проблема: что бы я ни делал, я не могу получить более 1 записи в секунду. Я очень надеюсь, что я делаю что-то не так

Что я делаю:

  1. Получить список всех записей из CRM с полем Guid и Key.
  2. Разделите записи на несколько задач.
  3. Создайте ExecuteMultipleRequest в каждой задаче с помощью Create или Update в зависимости от того, существует ли запись в предыдущем списке из (1).
  4. Создайте один OrganizationService для каждого потока (повторно используемый между последовательными потоками в стиле циклического перебора (см. код ниже)).
  5. Запустите выполнение нескольких.
  6. Плакать из-за скорости.

Результат не зависит от количества параллельных задач или размера партии. Это в основном ВСЕГДА около 0,9-1,5 записей в секунду.

Я пробовал все от 1 темы с 1000 штук до 16 потоков по 1 штуке в каждой.

Этот пост, утверждающий, что 200-300 записей в секунду возможны, насмехается над чем-то жестоким: зло дразнящий пост в блоге с 300 записями в секунду для CRM онлайн

Фрагменты кода из проекта (пытался скопировать только то, что может быть актуально):

Создание контекста.

 foreach (int i in Enumerable.Range(1, _MaxThreads * 2))
 {
    var crmConnection = CrmConnection.Parse(connectionString);
    var organisationservice = new OrganizationService(crmConnection);
    _OrgServiceList.Add(organisationservice);
 }

Как я создаю свои задачи:

private void ImportNewBatch(List<Customer> dataSet)
{
    var service = _OrgServiceList[_CurrentServicePosition];
    _CurrentServicePosition++;

    if (_CurrentServicePosition >= _OrgServiceList.Count)
        _CurrentServicePosition = 0;

    var aTask = new Task(() => WorkerThread(dataSet, service), TaskCreationOptions.None);
    aTask.Start();
    _RunningThreads.Add(aTask);

    if (_RunningThreads.Count >= _MaxThreads)
        Task.WaitAny(_RunningThreads.ToArray());

    _RunningThreads.RemoveAll(t => t.IsCompleted);
}

Выполнить множественный запрос

var requestWithResults = new ExecuteMultipleRequest()
{
    Settings = new ExecuteMultipleSettings()
    {
        ContinueOnError = true,
        ReturnResponses = true
    },
    Requests = new OrganizationRequestCollection()
};

Обновление 1. Получен полунеофициальный ответ от Microsoft относительно CRM в Интернете, который может быть интересен и другим:

  • Хорошая производительность для CRM онлайн составляет около 10 записей в секунду.
  • Производительность сильно зависит от того, есть ли у вас плагины или нет.
  • CRM Online регулирует множественные запросы, так что только два (2) могут выполняться одновременно, все запросы после этих двух ставятся в очередь и обрабатываются по очереди.
  • CRM Проверяет ваш IP-адрес и логин, чтобы вы не могли обойти регулирование с несколькими пользователями или отдельными контекстами.
  • Наличие решения с большим количеством лицензий даст вам большую производительность, т. е. при прочих равных условиях экземпляр со 100 лицензиями будет быстрее, чем экземпляр с 5.

person JensB    schedule 10.02.2015    source источник
comment
2-300 в секунду никогда не бывает, я тоже это тестировал, и через sdk я получил около 5/10 записей в секунду в онлайн-среде, на самом деле, как только вы делаете запрос к crm из консольного приложения, время, которое требуется, как вы сказали, составляет около 0,7-1,5 секунды. Чтобы улучшить его работу, вы можете решить проблему, выполнив предварительную обработку за один раз. Я имею в виду, что нужно разрешить все поиски за один раз, а затем отправлять данные без проверки CRM каждый раз.   -  person Mauro De Biasio    schedule 13.03.2015


Ответы (4)


Вы всегда будете ограничены производительностью, которую Dynamics CRM Online предоставляет вашему экземпляру. Я знаю, что в локальных сценариях мне удавалось выполнять десятки тысяч вставок в секунду (обычные записи без запущенных плагинов/рабочих процессов).

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

Вы можете прочитать некоторые основные сведения об использовании Распространитель сбалансированных данных с CRM в блоге партнера Sonoma. Я бы скопировал его сюда, но там не так много кода и в основном изображения.

person Nicknow    schedule 12.02.2015

Вы можете одновременно иметь два ExeucteMultipleRequest в CRM. Поэтому нет смысла пытаться иметь более двух потоков.

Убедитесь, что вы максимизируете количество запросов, выполняемых в одном вызове ExecuteMultipelRequests. Из вашего объяснения того, что вы делаете, похоже, что вы отправляете только один запрос на обновление/создание в CRM за раз.

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

Также немного неуверен в том, как вы используете создание организационных связей заранее. Если вы поместите 1000 обновлений в один запрос (по 1 в секунду), выполнение этого одного запроса займет почти 17 минут. Создание новой службы занимает меньше секунды, поэтому вы можете также создать новую службу для каждого запроса, просто чтобы убедиться, что у вас нет проблемы с многопоточностью, поскольку служба организации не является многопоточной.

person Daryl    schedule 11.02.2015

Не удается легко найти информацию об использовании многопоточности компонента скрипта для служб SSIS, так что только попытка, которая может вам помочь.

Вот как вы делаете Task создание:

var aTask = new Task(() => WorkerThread(dataSet, service), TaskCreationOptions.None);
aTask.Start();

Здесь вы предоставляете только делегата для выполнения и никакой другой информации. Компонент Script по умолчанию может быть однопоточным, поэтому все ваши задачи выполняются прямо в основном потоке, без использования ThreadPool.

Рассмотрите возможность создания Task с предоставлением TaskScheduler.Default, так как он будет использовать все ресурсы, которые он можно быстро добиться результата:

TaskFactory.StartNew(delegate here, null, TaskCreationOptions.None, TaskScheduler.Default)

Итак, другие проблемы в вашем коде:

if (_RunningThreads.Count >= _MaxThreads)
    Task.WaitAny(_RunningThreads.ToArray());

Это плохая практика. По умолчанию ThreadPool лучше знает, продвигать ли ему какое-то задание или нет.

aTask.Start();

Рассмотрим использование async\await здесь, так как это будет более эффективно для вашего кода.


Обновление: я думаю, что ThreadPool не будет запускать одновременно количество задач, превышающее количество процессоров. Вы можете легко проверить его на своей машине, просто изучив его внутренние свойства, но, насколько я помню, в каждый момент времени он близок к 4.

согласно MSDN:

Количество операций, которые можно поставить в очередь в пул потоков, ограничено только доступной памятью; однако пул потоков ограничивает количество потоков, которые могут быть одновременно активны в процессе.
Начиная с .NET Framework 4 размер пула потоков по умолчанию для процесса зависит от нескольких факторов. факторов, таких как размер виртуального адресного пространства. Процесс может вызвать метод GetMaxThreads, чтобы определить количество потоков.
Вы можете контролировать максимальное количество потоков с помощью GetMaxThreads и SetMaxThreads методы.

person VMAtm    schedule 10.02.2015
comment
ThreadPool знает лучше. Всегда ли это так, даже если задача выполняет вызовы веб-сервиса, и каждый вызов может иметь тайм-аут 60 секунд? Что это за запуск 500 из них, а служба на другом конце не может ответить в течение заданного времени? - person JensB; 10.02.2015
comment
@JensB Обновил ответ. - person VMAtm; 10.02.2015
comment
Реализовал эти вещи, но производительность не изменилась. Добавлено обновление с несколькими специфическими вещами CRM, которые я узнал от MS. Возможно, я не могу получить больше скорости, чем я. Но благодаря вам я узнал кое-что о задачах :) - person JensB; 11.02.2015

Я должен не согласиться с комментарием Дайрла о двух нитях; в On Premise CRM ограничение на 2 потока не применяется; не за компанию или что-то. Я использовал executeMultiple с 50 потоками для одной и той же компании. Но вы должны быть осторожны, чтобы не отправлять несколько запросов ExecuteMultiple через один и тот же OganizationProxy. Как указано в документации MSDN, прокси-серверы организации не являются потокобезопасными. Самый простой способ убедиться, что вы используете разные прокси-серверы, — это создать пул прокси-серверов организации. Возможно, хитрость здесь в том, что у вас есть несколько сеансов веб-сервера.

Используя этот метод, я могу загрузить ЦП 16-ядерной CRM-машины и увеличить количество вставок в секунду до тех пор, пока моим ограничением не станет диск SQL-сервера. Я сделал это, используя локальную сущность CRM. То есть, если вы создаете новую сущность в CRM, принимая все значения по умолчанию. Используя эту технику, я добился 3900 вставок в секунду, используя две машины 16 CORE CRM FE. Это было без настройки пула потоков .Net.

Забытый технический документ, Microsoft Dynamics CRM 2011 Data Load Performance and Практический пример масштабируемости, обсуждает использование 10 потоков на сервер. Но я использовал более 10 потоков с executeMutliple для одного и того же сервера и одной и той же организации до такой степени, что у меня 97% использования ЦП на нескольких серверах.

person user5278381    schedule 28.08.2015
comment
charlesdwm — пользователь 5278381 - person user5278381; 28.08.2015