Балансировка нагрузки с общими приоритетными очередями
Я пытаюсь реализовать балансировщик нагрузки в данный момент и немного ударил по скорости. Ситуация следующая (упрощенная),
- У меня есть очередь запросов queue_a, которые обрабатываются worker_a
- Есть вторая очередь запросов queue_b, которые обрабатываются worker_b
- И у меня есть третья очередь запросов queue_c, которая может идти к любому из рабочих
Причиной такого рода настройки является то, что у каждого работника есть уникальные запросы, которые может обрабатывать только он, но есть и общие запросы, которые может обрабатывать каждый.
Я собирался реализовать это в основном, используя 3 экземпляра C5 IntervalHeap. Каждый работник будет иметь доступ к своей локальной очереди + общим очередям, частью которых он является (например, worker_a может видеть queue_a & queue_c).
Проблема с этой идеей заключается в том, что если в локальной очереди есть запрос и в общей очереди (ях) с одинаковым приоритетом, невозможно узнать, какая из них должна быть обработана первой (IntervalHeap обычно является первым прибывшим первая подача, когда это произойдет).
РЕДАКТИРОВАТЬ: я обнаружил, что IntervalHeap, похоже, не является первым пришел-первым-сервером с одинаковыми приоритетами запросов!
Я хотел бы минимизировать блокировку между очередями, так как она будет относительно высокой пропускной способностью и чувствительной ко времени, но единственный способ, который я могу придумать в данный момент, заключается в гораздо большей сложности, когда третья очередь удаляется, а общие запросы помещаются в обе queue_a и queue_b. Когда запрос будет обработан, он будет знать, что это общий запрос, и ему придется удалить его из других очередей.
Надеюсь, это объясняет это достаточно ясно!
2 ответа
Похоже, что в итоге вы просто вытолкнете пузырь - независимо от того, как вы его устроите, в худшем случае у вас будет три одинаковых приоритета для выполнения только двумя работниками. Какие критерии разрыва связей вы могли бы применить вне приоритета, чтобы выбрать, из какой очереди вытащить следующую задачу?
Вот две идеи:
Выберите очередь наугад. Все приоритеты равны, поэтому не важно, какой из них выбран. В среднем в худшем случае все очереди будут обслуживаться примерно с одинаковой скоростью.
Минимизируйте длину очереди, беря из очереди наибольшее количество элементов. Это может вызвать некоторое голодание других очередей, если скорость заполнения одной очереди постоянно выше, чем у других.
НТН
Синхронизация ваших работников может совместно использовать тот же пул ресурсов, что и их личная очередь. Если в очереди есть 1 элемент для работника 1 и 1 элемент в общей очереди, было бы обидно, если рабочий 1 первым заберет элемент общей очереди, поскольку это ограничит параллельные запуски. Скорее, вы хотите, чтобы работник 1 сначала поднял личный элемент, однако это приводит к появлению новых предостережений, в которых работник 1 и работник 2 заняты обработкой личных элементов, и поэтому старые общие элементы не будут выбраны.
Найти решение, которое решит эти проблемы, будет очень сложно, если вы попытаетесь уменьшить сложность. Простая реализация заключается в обработке общих элементов только в том случае, если личная очередь пуста. Это не затрагивает ту часть, где приоритеты не обрабатываются правильно при сценарии высокой нагрузки. (например, где общая очередь не будет обрабатываться, поскольку частные очереди всегда заполнены). Чтобы сбалансировать это, вы можете сначала обработать личную очередь, только если личная очередь других работников пуста. Это все еще не идеальное решение, так как при этом предпочтение будет отдаваться частным элементам очереди по сравнению с общими. Решение этой проблемы снова может быть достигнуто путем настройки нескольких стратегий, но здесь возникает еще более сложная задача.
Все зависит от ваших требований.