Приоритизация задач Netty в ThreadPoolExecutors - PullRequest
5 голосов
/ 15 ноября 2011

У меня есть сервер, реализованный в netty, который обрабатывает запрос пользователя, обращается к промежуточному программному обеспечению и отправляет ответ.Ожидается, что ввод-вывод будет незначительным по сравнению с циклическим переходом к промежуточному программному обеспечению, поэтому для минимизации блокировки у меня есть ExecutionHandler в конвейере поверх OrderedMemoryAwareThreadPoolExecutor.Пока никаких проблем.

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

Я реализовал простой ThreadPoolExecutor, который использует PriorityBlockingQueue и устанавливает приоритет на основе данныхизвлечено из нашего собственного класса Session (присоединено к контексту в ChannelHandler).Опять же, проблем пока нет.

Сложность возникает при попытке воспользоваться преимуществами упорядочения и осведомленности о памяти встроенных в NetPy ThreadPoolExecutors.В идеале MyThreadPoolExecutor может просто расширить OrderedMemoryAwareThreadPoolExecutor и подключиться к приоритетной очереди.Увы, это невозможно по двум причинам: частное и окончательное.Более подробно:

a) ThreadPoolExecutor.workQueue может быть установлен в его конструкторе, но MemoryAwareThreadPoolExecutor жестко кодирует это как LinkedTransferQueue и не предоставляет его своему дочернему элементу OrderedMemoryAwareThreadPoolExecutor (то есть MyThreadPoolExecutor не имеет доступаустановить его).При необходимости это может быть преодолено с помощью некрасивой настройки приватного поля на основе отражения.

b) Я хотел бы иметь возможность переопределить MyThreadPoolExecutor.doUnorderedExecute (), чтобы я мог вставить обработку приоритетов ипостроить необходимые объекты, но он объявлен окончательным.Код, который вызывает его, менять не нужно.

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

Теперь несколько вопросов:

1) Решаю ли я не ту проблему?Неужели я лаю совсем не по тому дереву ради того, чего я хочу достичь?

2) Если нет, есть ли лучший способ сделать это, чем обсуждалось выше?

3) Приведенный выше подходЭто может привести к нехватке ресурсов для приоритетных задач, когда общая нагрузка на сервер постоянно находится в пределах емкости.Я готов смириться с этим для «непослушных» пользователей, но как только они вернутся в нормальное состояние, их существующие задачи будут по-прежнему голодать, и для сохранения порядка следует добавить любые новые задачи с более высоким приоритетом.Есть ли у вас какие-либо рекомендации, как лучше всего с этим бороться?(Запрещение пользователей запрещено бизнесом.)

4) Это половина вопроса, половина обратной связи.Документация netty для OrderedMemoryAwareThreadPoolExecutor содержит удобную диаграмму для потока X & Y - возможно, это потоки, объединенные в ThreadPoolExecutor, а не рабочие потоки ввода-вывода?Возможно, стоит сделать это более понятным.Кроме того, когда не используется ExecutionHandler, каждый канал связан с одним рабочим потоком ввода-вывода - так ли это в случае с ExecutionHandler?т. е. порядок добавления задач в ExecutionHandler гарантированно совпадает с порядком их поступления на канал?Если это так, то я не могу видеть, как поток X в документах для MemoryAwareThreadPoolExecutor мог обработать событие 2 до события 1 - я принимаю, что здесь разные потоки могут завершать работу в любом порядке, но я не вижу, как работа может бытьприсваивается той же теме не по порядку (она выскакивает из workQueue).Документы в ExecutionHandler намекают на это, но выиграли бы немного больше деталей.

Большое спасибо за чтение, и любая помощь высоко ценится.

Ответы [ 2 ]

3 голосов
/ 17 ноября 2011

1) Нет, с твоей идеей все в порядке. Просто OrderedMemoryAwareThreadPoolExecutor не хватает такой возможности. Вы бы подали вопрос ?

2) Я бы просто раскошелил OrderedMemoryAwareThreadPoolExecutor, упростил бы его и добавил приоритетную очередь. Таким образом, вы получаете гораздо больше контроля над тем, как обрабатываются элементы очереди (события).

3) Вместо использования приоритетной очереди у вас может быть две очереди - одна для элементов с высоким приоритетом и другая для элементов с более низким приоритетом. Поток может сначала обработать очередь с высоким приоритетом, но вы можете управлять циклом, чтобы он не оставался там слишком долго.

4) Да, это темы из ThreadPoolExecutor. Если не ясно, мы должны обновить нашу документацию. Пожалуйста, не стесняйтесь подавать проблему или вносить свой вклад напрямую, подписав ее.

0 голосов
/ 15 ноября 2011

Ваше решение «тревожный звонок» выглядит знакомо - просто начните с небольшого размера пула.

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

...