Мы в очереди и сериализации правильно?


13

Мы обрабатываем сообщения с помощью различных сервисов (одно сообщение будет касаться, вероятно, 9 сервисов, прежде чем оно будет выполнено, каждое из которых выполняет определенную функцию, связанную с IO). Прямо сейчас у нас есть комбинация наихудшего случая (сериализация контракта данных XML) и наилучшего (производительность в памяти MSMQ) для производительности.

Характер сообщения означает, что наши сериализованные данные занимают около 12-15 килобайт, и мы обрабатываем около 4 миллионов сообщений в неделю. Постоянные сообщения в MSMQ были слишком медленными для нас, и по мере роста данных мы ощущаем давление со стороны отображаемых в памяти файлов MSMQ. Сервер использует 16 ГБ памяти и продолжает расти, просто для очередей. Производительность также страдает, когда использование памяти велико, так как машина начинает обмениваться. Мы уже выполняем самоочищение MSMQ.

Я чувствую, что есть часть, которую мы делаем неправильно здесь. Я пытался использовать RavenDB для сохранения сообщений и просто ставить в очередь идентификатор, но производительность там была очень медленной (в лучшем случае 1000 сообщений в минуту). Я не уверен, является ли это результатом использования версии для разработки или чего-то еще, но нам определенно нужна более высокая пропускная способность [1]. Концепция сработала очень хорошо в теории, но производительность не соответствовала задаче.

Шаблон использования имеет один сервис, выполняющий роль маршрутизатора, который выполняет все операции чтения. Другие сервисы будут прикреплять информацию, основанную на подключении сторонних производителей, и пересылать обратно к маршрутизатору. Большинство объектов касаются 9-12 раз, хотя около 10% вынуждены обходиться в этой системе некоторое время, пока третьи стороны не отреагируют соответствующим образом. Службы прямо сейчас учитывают это и имеют соответствующие спящие режимы, поскольку по этой причине мы используем поле приоритета сообщения.

Итак, мой вопрос: что такое идеальный стек для передачи сообщений между компьютерами с дискретной, но локальной сетью в среде C # / Windows? Я бы обычно начинал с BinaryFormatter вместо XML-сериализации, но это кроличья нора, если лучшим способом будет переложить сериализацию в хранилище документов. Отсюда и мой вопрос.

[1]: характер нашего бизнеса означает, что чем раньше мы обрабатываем сообщения, тем больше мы зарабатываем. Мы эмпирически доказали, что обработка сообщения в конце недели означает, что мы с меньшей вероятностью заработаем эти деньги. В то время как производительность «1000 в минуту» звучит достаточно быстро, нам действительно нужно это число выше 10k / мин. То, что я даю цифры в сообщениях в неделю, не означает, что у нас есть целая неделя для обработки этих сообщений.

=============== изменить:

Дополнительная информация

Основываясь на комментариях, я добавлю некоторые разъяснения:

  • Я не уверен, что сериализация является нашим узким местом. Я провел сравнительный анализ приложения, и хотя сериализация действительно отображается на графике, она отвечает только за 2,5-3% загрузки ЦП службы.

  • Меня больше всего беспокоит постоянство наших сообщений и потенциальное неправильное использование MSMQ. Мы используем нетранзакционные, непостоянные сообщения, чтобы мы могли поддерживать производительность в очереди, и мне бы очень хотелось, чтобы по крайней мере постоянные сообщения оставались после перезагрузки.

  • Добавление дополнительной оперативной памяти является мерой временного ограничения. Машина уже ушла с 4 ГБ -> 16 ГБ ОЗУ, и становится все труднее снимать ее, чтобы продолжать добавлять больше.

  • Из-за паттерна маршрутизации «звезда» приложения, половина времени, когда объект извлекается, а затем помещается в очередь, не меняется вообще. Это снова позволяет (IMO) хранить его в каком-либо хранилище значений ключей в другом месте и просто передавать идентификаторы сообщений.

  • Шаблон звездообразной маршрутизации является неотъемлемой частью приложения и не изменится. Мы не можем применять его к многоножкам, потому что каждая часть в процессе работы работает асинхронно (методом опроса), и мы хотим централизовать поведение повторов в одном месте.

  • Логика приложения написана на C #, объекты являются неизменяемыми POCO, целевая среда развертывания - Windows Server 2012, и нам разрешено устанавливать дополнительные компьютеры, если конкретный фрагмент программного обеспечения поддерживается только в Linux.

  • Мои цели - поддерживать текущую пропускную способность, уменьшая объем памяти и повышая отказоустойчивость при минимальных затратах капитала.


Комментарии были очищены, поскольку соответствующие вопросы были включены в вопрос.
ChrisF

Было бы целесообразно решить наиболее насущную проблему, прежде чем беспокоиться о замене подсистем очередей (хотя это, возможно, все же стоит сделать в конечном итоге). Тот факт, что память выходит из-под контроля, говорит о том, что где-то все еще есть утечки. Какое (если есть) профилирование памяти было выполнено?
Дэн Лайонс

@DanLyons: единственный рост памяти происходит в MSMQ. Никто на самом деле не говорит об этом, но, похоже, это из-за непостоянных сообщений, которые все отображаются в памяти. Поскольку мы сериализуем много данных, они сохраняют значительный объем выделяемой памяти. Память (в конечном итоге) освобождается по мере использования сообщений и выполнения внутренней очистки MSMQ.
Брайан Бетчер

Ответы:


1

Вот некоторые тесты очереди, которые могут вас заинтересовать. MSMQ должен обрабатывать 10K сообщений в секунду. Может ли это быть проблема конфигурации или, возможно, клиенты не успевают за чтением очереди? Также обратите внимание на то, насколько быстрым является ZeroMQ в этих тестах (около 100 Кбайт сообщений в секунду), он не предлагает опцию постоянства, но должен привести вас туда, где вы хотите быть мудрыми по производительности.


4

У нас была несколько похожая ситуация несколько лет назад, с системой сообщений в очереди (аудио-отпечатки пальцев в нашем случае). Мы высоко ценили постоянство пакетов данных в очереди, но выяснили, что постановка всего на диск и использование очереди с диска была очень дорогой.

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

Мы разработали очередь, которую мы окрестили VMQueue (для Очереди виртуальной памяти, очень плохое имя в ретроспективе). Идея этой очереди состоит в том, что, если процесс потребителя работает на должном уровне, другими словами, обрабатывая достаточно быстро, чтобы иметь возможность поддерживать число помещенных в очередь элементов ниже определенного уровня, то он в основном имеет ту же производительность, что и память. основанная очередь. Однако, когда потребитель замедляется или становится недоступным, а очередь производителя увеличивается до определенного размера, тогда очередь автоматически начнет пейджинг элементов на диск и с диска (используяBinaryFormatterкстати сериализация). Этот процесс позволяет полностью контролировать использование памяти, а процесс подкачки происходит быстро или, по крайней мере, намного быстрее, чем перестановка виртуальной памяти, происходящая при большой загрузке памяти. Как только потребитель успевает опустошить очередь ниже порогового значения, он возобновляет работу как чисто основанная на памяти очередь

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

Если вам интересно, я могу поделиться VMQueueисходным кодом класса, чтобы вы могли поиграть с ним. Очередь будет принимать любой класс, помеченный как Serializable. При создании очереди вы устанавливаете размер страницы в количестве элементов. Интерфейс класса практически не отличается от стандартного класса Queue. Однако код очень старый (.net 1.1), поэтому, к сожалению, универсального интерфейса не существует.

Я знаю, что переход от проверенной технологии MSMQ - огромная ставка, однако эта очередь надежно работала почти 6 лет и позволила нам выжить и оправиться от сценариев, когда машина-производитель была отключена в течение нескольких недель! Пожалуйста, дайте мне знать, если вы заинтересованы. :)


1

Система HP ProLiant ML350G5 получает 82 тыс. Транзакций в минуту, т. Е. Она в 8 раз превышает пропускную способность «10 тыс. В минуту», о которой вы упоминали.

Производительность: 82,774 т / мин

Кроме того, если честно, я бы просто использовал 64 или даже 128 ГБ ОЗУ - ОЗУ дешево. Гринспен указывает на разницу между «бросить ОЗУ в него» и «найти умного парня с MIT, чтобы оптимизировать его», и ОЗУ побеждает.

В итоге у него был компьютер с SQL Server, оснащенный 64 ГБ ОЗУ, и несколько внешних компьютеров, на которых выполнялись страницы ASP.NET ... Сайт swaptree.com обслуживает в настоящее время более 400 000 пользователей (быстро растет). без затруднений ...

Заметьте, что «машина уже заняла 16 ГБ оперативной памяти» - это далеко не достаточно. В статье указывается сервер, который обрабатывает 400 тыс. Пользователей на 64 ГБ оперативной памяти.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.