Почему MSMQ быстрее, чем WCF QueueService?
У меня есть собственная служба WCF на консоли с привязкой netNamedPipeBinding
. Служба имеет только один пустой метод Send(DataTable bulk)
[ServiceContract]
public interface IWcfQueueService
{
[OperationContract]
void Send(DataTable bulk);
}
public class WcfQueueService : IWcfQueueService
{
public void Send(DataTable bulk)
{
// Here would be something like _bulks.Add(bulk);
// BUT, for now it is empty method and still it slower than MSMQ
}
}
Мой клиент получает 200-килобайтные входы от БД и обрабатывает его с помощью нашего BoundedThreadPool (только создает, допустим, 20 потоков). Каждый вход обрабатывается с помощью другого потока. Каждый поток выполняет MyMethod
, а в конце MyMethod
результат добавляется к bulkManager
.
public void MyMethod(string input)
{
var res = ProcessInput(input);
bulkManager.Add(res);
}
Когда bulkManager
накапливает N элементов (= объем), он передает основную часть другому потоку, все, что он делает, представляет собой очередь, которая содержит один из двух методов:
- Если wcf включен:
wcfQueueService.Send(bulk);
- else, если включен MSMQ:
new MessageQueue(@".\private$\q").Send(new Message {Body = bulk});
Все два метода работают, но MSMQ работает намного быстрее. С клиентом MSMQ удается обрабатывать около 80 тыс. Штук в 20секундах, а с wcf всего 20 КБ-30 тыс. Штук.
Я не понимаю, почему это происходит. Мой WCF работает в разных процессах, таких как MSMQ. Кроме того, мой WCF ничего не хранит, у него есть пустой метод. Итак, почему MSMQ выигрывает WCF?
Обновление
Как leppie
предложил попробовать .NetRemoting. NetRemoting действительно улучшил скорость. Клиент обработал 60K. Но,
- Он все еще медленнее, чем MSMQ
- Как я читал .Net Remoting устарел WCF, а WCF должен быть быстрее, чем .Net Remoting в соответствии с this, так почему я получаю что мой wcf медленнее? Может быть, моя привязка неверна?
Ответы
Ответ 1
Вы не сравнитесь с подобными.
Самое очевидное различие заключается в том, что в случае WCF ваши тайминги включают выполнение всего стека каналов служебной стороны и вызов операции, тогда как ваш прямой случай MSMQ измеряет время для размещения полезной нагрузки на стороне клиента. Имейте в виду, что обработка служебной стороны в WCF включает десериализацию вашего объекта DataTable, что, вероятно, довольно дорого, если ваш фактор увеличения N велико.
Более того, в зависимости от того, как вы настроили ручку настройки обслуживания и дросселирования, запросы от клиента могут выполняться быстрее, чем служба настроена для обработки, в результате чего сами запросы ставятся в очередь для выполнения на сервисная сторона.
Кроме того, в зависимости от того, как вы настроили привязку, могут быть и другие существенные различия, например, безопасность. Кстати, действительно ли вы использовали NetNamedPipeBinding (как заявляет ваш вопрос), а не NetMsmqBinding, поскольку название, казалось, подразумевало? Если это так, используя конфигурацию привязки по умолчанию, у вас будет полностью ненужное шифрование и подписание каждого массового сообщения, которое не происходит в вашем прямом MSMQ. Эти криптографические операции с большими сообщениями также будут относительно дорогими.
Лучшее сравнение было бы с работой WCF, определенной как OneWay.
Ответ 2
Можете ли вы предоставить пример кода, который показывает поведение, которое вы видите?
Я провел собственное тестирование, создав 20 000 сообщений для отправки. Я попробовал оба, 20 000 с прямым MSMQ и 20 000 с WCF, абстрагирующими конечную точку MSMQ для меня.
20 000 с прямым MSMQ использовали 64,75% процессорного времени, а версия WCF, отправляющая 20 000 сообщений, использовала 34,16% времени процессора (с использованием функции анализа в Visual Studio Ultimate).
Если бы я не сделал ошибку на моем конце, версия WCF была почти в два раза быстрее, чем эквивалент MSMQ с жесткой кодировкой.
Ответ 3
Я думаю, что разница в том, что происходит в вашей работе WCF, чем то, что MSMQ делает, когда оно принимает запрос.
Я ожидаю, что метод, который выполняется, когда вы вставляете сообщение с MSMQ simple, принимает сообщение и ничего больше. Некоторые работники делают тяжелый подъем.
В вашей операции вам необходимо передать запрос одному экземпляру обработчика запросов. Экземпляр обработчика запроса должен быть создан, когда служба "развернута".
Вы также можете найти улучшенную производительность, используя параллельную библиотеку задач в .NET 4, чтобы распараллелить ваши запросы.