2014-10-01 2 views
7

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

Обычно для Джерси необходимо создать один поток для запроса. И, похоже, это так: пользуюсь ли я (где Джерси создает темы для меня - я исследовал это в отладчике), или нет (где я, очевидно, должен сам создавать темы).

Так вот одна конкретная ситуация, в которой это не достаточно хорошо:

Я HTTP размещения на удаленных серверах, со скоростью до 500 запросов/сек. Но поскольку ответ может занять некоторое время (я рассчитываю до 30 секунд), общее количество потоков может достигать нескольких тысяч (в этот момент процесс JVM обычно сбой). Более того, просто безумие создавать столько потоков. На самом деле это должен быть кусок торта для доступных ресурсов процессора/сети/ОС для борьбы с этой нагрузкой.

Итак, что бы я хотел сделать, это просто отключить запросы и получать информацию от ОС, когда поступит HTTP-ответ.

  • Как сказано выше, просто используя target.request(...).async().... не делает трюк (потому что тогда Джерси просто порождает собственные потоки).
  • Кроме того, ограничение количества потоков через new ClientConfig().property(ClientProperties.ASYNC_THREADPOOL_SIZE, 10) не является полезным вообще, поскольку это означает, что не более 10 запросов будут отправляться за раз, что явно не то, что я хочу (он просто нагромождал очередь).

Я экспериментировал с new ClientConfig().connectorProvider(new GrizzlyConnectorProvider()), чтобы получить поддержку NIO, но не видел никаких различий в поведении.

Итак, есть ли способ погасить запрос без необходимости создавать один дополнительный поток для каждого запроса?

+0

Я только что нашел, что существует [jersey-non-blocking-client] (http://search.maven.org/#artifactdetails%7Ccom.sun.jersey.contribs%7Cjersey-non-blocking-client%7C1 .18.1% 7Cjar) и соответствующее [сообщение в блоге] (https://blogs.oracle.com/PavelBucek/entry/jersey_non_blocking_client), где автор решает проблему (хотя он серьезно недооценивает влияние неблокирующих и блокирующих). Однако, к сожалению, проект предназначен для старой версии Джерси, которую я не могу использовать. Может быть, новые версии Джерси уже поставляются с неблокирующей поддержкой? И если да, как его активировать? –

+0

Количество потоков, которые вы можете запустить, во-первых, является вопросом кучи пространства. В 2048 году нет ничего волшебного. – EJP

+0

@ EJP: Спасибо, я исправил вопрос. –

ответ

4

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

<dependency> 
    <groupId>org.apache.httpcomponents</groupId> 
    <artifactId>httpasyncclient</artifactId> 
    <version>4.0.1</version> 
</dependency> 

Надеюсь, это поможет.

+0

В конце концов, я пошел с Apache HttpAsyncClient (я также попробовал AsyncHttpClient, как было предложено @Alper, что также отлично работает - просто небольшие различия). Насколько я могу судить, текущие версии Джерси не могут доставить неблокирующее поведение, потому что он ограничен JAX-RS 2.0 (несколько [мест] (http://java.dzone.com/articles/whats-new-jax -rs-20) упомянуть, что это может стать возможным с JAX-RS 3.0) –

1

Сделайте ваши запросы, используя https://github.com/AsyncHttpClient/async-http-client, в нем используется нетти. Он уволит вызовы из потока запросов и обратится к вашему коду, поэтому он не связывает потоки запросов контейнера.

+0

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

+0

Мы используем Джерси для наших конечных точек обслуживания, и когда нам требуется вызов другой услуги, мы используем AsyncHttpClient. Если вы уже используете джерси-клиент, я думаю, что это не может быть очень легко изменить. Вы можете использовать ExecutorService и будущее, чтобы отключить вызывающий поток и выполнить одно и то же. Я добавлю еще один пример. –

+0

Использование моего собственного ThreadPool на самом деле не решает проблему: если ThreadPool ограничен, и я использую вызовы синхронизации в Джерси, тогда блокирующие исполнители блокируют. Если я использую асинхронные вызовы на Джерси, тогда Джерси, к сожалению, создает свои собственные потоки (а не только рабочие, но по одному на открытый запрос) ... (единственное, что могло бы работать, - это использовать вызовы синхронизации, а затем убить мою нить - но это похоже на очень плохую идею.) –