Структура потребителя производителя не очень хорошо масштабируется.
Чем больше у вас производителей или потребителей, тем хуже вы получаете производительность. Причина в том, что общая очередь становится узким местом для всей системы. Я надеюсь, вы видите, как.
Лучший подход - не иметь общей очереди; У каждого потребителя должна быть своя собственная очередь. Когда приходит запрос, он идет к балансировщику нагрузки. Балансировщик нагрузки поместит запрос в очередь потребителя, которая является самой маленькой. Балансировщик становится узким местом, но он не выполняет много операций - просто выбирает правильную очередь для отправки входящего запроса - так что его нужно чертовски быстро.
Вот edit , чтобы ответить на ваши вопросы:
Проблема (подробнее) : чем больше ядер, тем медленнее становится. Зачем? Общая память.
@ Peyman use ConcurrentLinkedQueue (это неблокирующая очередь без ожидания, в которой одновременно может выполняться одна очередь и одна очередь). Даже попробуйте это в своем первоначальном проекте и сравните оба проекта. Я ожидаю, что ваш пересмотренный дизайн будет работать лучше, потому что вы можете иметь только 1 очередь и 1 очередь одновременно, в отличие от одной очереди и очереди n, как в первоначальном проекте (но это только мои предположения).
A Отличная статья о масштабируемой потребительской продукции с использованием балансировщиков
Чтение этой страницы (или можно посмотреть только на "переход с подхода с общей рабочей очередью на подход с очередью на поток")
Вот список из http://www.javaperformancetuning.com/news/newtips128.shtml. Я думаю, что последние 3 пункта более применимы к вам:
- Большинство серверных приложений используют общую рабочую очередь и пул потоков; общая рабочая очередь содержит короткие задачи, поступающие из удаленных источников; пул потоков извлекает задачи из очереди и обрабатывает задачи; потоки блокируются в очереди, если нет задачи для обработки.
- Очередь фидеров, разделяемая между потоками, является узким местом доступа (из-за конфликта), когда число задач велико, а время задания очень мало. Узкое место ухудшается с увеличением количества используемых ядер.
- Решения, доступные для преодоления конфликтов при доступе к общей очереди, включают: использование структур данных без блокировки; Использование параллельных структур данных с несколькими блокировками; Поддержание нескольких очередей для изоляции конфликта.
- Подход «очередь на поток» устраняет конфликт доступа к очереди, но не оптимален, когда очередь очищается, когда в других очередях находятся необработанные данные в очереди. Чтобы улучшить это, свободные потоки должны иметь возможность украсть работу из других очередей. Чтобы свести к минимуму конкуренцию, «кража» должна выполняться из хвоста другой очереди (где обычное удаление из собственной очереди потока выполняется из начала очереди).