OkHttpClient — оптимальный ThreadPoolTaskExecutor

Пытаюсь понять наилучший возможный Java ThreadPoolTaskExecutor, который я могу определить при передаче в OkHttpClient, с точки зрения задержки. В настоящее время наше определение следующее:

<property name="corePoolSize" value="#{ T(java.lang.Math).max(32,numCpu) * 2 }" />
<property name="maxPoolSize" value="#{ T(java.lang.Math).max(32,numCpu) * 8 }" />
<property name="queueCapacity" value="200"/>

То есть максимальная емкость очереди (при которой будет открыт новый поток) равна 200, минимальное количество потоков равно max(32,numCpu) * 2, а максимальное количество потоков равно max(32,numCpu) * 8. В нашем случае numCpu может варьироваться от 16 до 24 (хотя, если учесть гиперпоточность, умножьте это число на *2, верно? ). Но если подумать, я не уверен, что количество потоков здесь должно быть как-то связано с количеством процессоров. Это отправка/получение потоков HTTP-клиента, а не потоков BusinessLogic. Так что, возможно, количество ЦП здесь не должно быть даже фактором.

Есть мнения/советы?


person Maxim Terletsky    schedule 20.10.2016    source источник
comment
Я не знаком с okhttpclient, но проделал большую работу в области распределенных вычислений на Java. Просто чтобы я лучше понял ваш вопрос, вы пытаетесь одновременно подключиться ко многим различным конечным точкам HTTP со своего клиента?   -  person CodeBlind    schedule 20.10.2016
comment
Ну, это сервер, который подключается к другим серверам. Я предполагаю, что это не столько разные конечные точки HTTP, сколько много-много HTTP-вызовов к нескольким заранее определенным конечным точкам.   -  person Maxim Terletsky    schedule 24.10.2016


Ответы (1)


Мне кажется, что ваш пул потоков используется для одновременного создания множества HTTP-соединений, а это означает, что ваша производительность ограничена не использованием ЦП, а вводом-выводом (и, возможно, памятью). «Оптимальное» количество потоков будет ограничено рядом других факторов...

<сильный>1. Скорость связи между вашим клиентом и конечными точками.

Допустим, ваш клиент подключен к каналу со скоростью 1 Гбит/с, но где-то дальше все ваши конечные точки могут обслуживать вас только со скоростью 1 Мбит/с. Чтобы максимально использовать локальную пропускную способность, вам потребуется одновременно запустить 1000 подключений, чтобы полностью использовать канал 1 Гбит/с, а это означает, что ваш пул потоков должен запускать 1000 потоков. Но это может быть проблематично и из-за другой проблемы...

<сильный>2. Использование памяти на поток не равно нулю, даже если они не делают ничего интенсивного.

Объем пространства стека по умолчанию, выделенный для Java, зависит от поставщика, но составляет порядка 1 МБ. Это не кажется чем-то большим, но если вам нужно запускать тысячи потоков, чтобы одновременно поддерживать как можно больше клиентских подключений, вам потребуется выделить гигабайты ОЗУ только для пространства стека. Вы можете настроить размер стека, выделенный для каждого потока, с помощью аргумента -Xss[size] VM, но он является глобальным для VM, поэтому уменьшение размера стека может вызвать проблемы в других областях вашей программы, в зависимости от того, что вы делаете.

<сильный>3. Средний размер HTTP-запроса.

Иногда все сводится к тому, сколько данных вы ожидаете передать за вызов POST/GET. Напомним, что для каждого TCP-соединения требуется начальное рукопожатие перед отправкой каких-либо данных. Если объем данных, которые вы ожидаете передать за время HTTP-вызова, очень мал, вы не сможете поддерживать тысячи подключений одновременно, даже если в вашем распоряжении тысячи потоков. Если сумма очень велика, может потребоваться всего несколько одновременных подключений, чтобы максимально использовать общую пропускную способность, доступную вашему клиенту.

Наконец...

Возможно, вы не сможете предсказать скорость каждого соединения, если все ваши конечные точки работают в Интернете. Я думаю, что лучшее, что вы можете сделать, это сравнить производительность различных конфигураций, учитывая каждый из этих факторов, и выбрать конфигурацию, которая, по-видимому, обеспечивает наилучшую производительность в вашей типичной операционной среде. Скорее всего, это будет где-то между N и 1000, где N — это количество ядер, которые вы запускаете, но чтобы свести это число к чему-то конкретному, потребуется немного усилий :)

person CodeBlind    schedule 24.10.2016