Tomcat и acceptCount не работают - PullRequest
0 голосов
/ 28 апреля 2018

Я использую tomcat 8 как часть проекта Spring Boot, и моя настройка acceptCount, похоже, не работает. Вместо того, чтобы принимать только 300 подключений, мой сервер принял почти 1000 подключений, которые я к нему подключил, хотя, конечно, обрабатывал не более 200 из них одновременно.

Кажется, что документация Tomcat ясна на acceptCount: «Максимальная длина очереди для входящих запросов на подключение, когда используются все возможные потоки обработки запросов. Любые запросы, полученные при заполнении очереди, будут отклонены». Но ясно, что этого не происходит.

Существует, конечно, другой параметр, maxConnections, и в его документации говорится: «Обратите внимание, что после достижения предела операционная система может по-прежнему принимать подключения на основе параметра acceptCount», но одно это примечание еще не означает acceptCount. это "считать сверху maxConnections, а не maxThreads" (как думает автор темы в https://coderanch.com/t/647733/application-servers/Tomcat-BIO-connector-configurations). Это просто означает, что он будет действовать в обоих случаях: когда все потоки обработки заняты и когда все доступные соединения исчерпаны. (И даже если этот парень был прав, это означало бы, что документация Tomcat совершенно неверна при определении acceptCount ...)

Тогда почему это игнорируется? Я нашел некоторые упоминания о дискуссиях, в которых люди якобы утверждали, что acceptCount не работает для них, но не нашли реальных обсуждений :( Даже наоборот, мне удалось найти некоторые жалобы на то, как Tomcat задыхается после 300 подключений (что по умолчанию maxThreads + acceptCount). Итак, я вижу, что для некоторых людей это работает, и меня просят поверить, что «возможно» для некоторых это не так. Не для меня тоже. Должен ли я верить, что руководство Tomcat неверно в некотором смысле что этот вариант не всегда соблюдается?

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

acceptCount для NIO передается в ServerSocket.bind(SocketAddress,int) в качестве 2-го параметра (отставание). Javadoc для этого метода говорит:

Аргумент backlog представляет собой запрошенное максимальное число ожидающие соединения на сокете. Его точная семантика является реализацией конкретный. В частности, реализация может налагать максимальную длину или можете полностью игнорировать параметр.

Похоже, это игнорируется в вашей JVM.

0 голосов
/ 07 мая 2018

Существуют сложные отношения между всеми этими настройками, и они еще более усложняются вашим выбором разъема (например, BIO, NIO, APR и т. Д.).

Разъем BIO практически не работает ... он не существует после Tomcat 8.0.x. Он не может принимать больше соединений, чем может обработать пул потоков одновременно. Следовательно, разъем BIO по существу составляет maxConnections == maxThreads. Следовательно, для соединителя BIO число соединений, которые сервер готов принять, должно быть maxConnections + acceptCount, но maxConnections ограничено некоторым относительно небольшим числом.

Другие более сложные коннекторы позволяют принимать в смысле TCP / IP для более чем одного соединения на поток. Значения по умолчанию для maxConnections ближе к 10k (зависит от конкретного типа). ), а размер пула потоков не имеет значения, поэтому число соединений, которые сервер готов принять, равно maxConnections + acceptCount.

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

Если вы используете BIO, я ожидаю, что соединения прервутся после, например, 300 подключений (вы не опубликовали свою конфигурацию, поэтому невозможно сказать, какие будут действительные цифры), но для NIO я ожидаю, что она будет к северу от 10 тыс. Подключений.

Для тестирования важно, чтобы вы ничего не делали со своим соединением, чтобы правильно их подсчитать. По сути, вам нужно сделать это:

foreach(i from 0..10301)
    conn[i] = connect('host:port')

Вы должны обнаружить, что есть некоторый i, для которого сервер не будет принимать соединение. Если вы подключитесь и выдадите GET /, сервер ответит, а соединения и потока обработки запросов вернутся в соответствующие пулы.

** ОБНОВЛЕНИЕ после прочтения некоторых комментариев **

Я ожидаю, что смогу обрабатывать одновременно 200 запросов, но Tomcat с радостью поставит в очередь еще 800 запросов. Дополнительные 200 в acceptQueue ставятся в очередь в стеке TCP / IP операционной системы, а не в Tomcat / Java

Предполагая бесконечное время ожидания чтения для клиентов, я ожидаю, что вы сможете запустить 1201 экземпляр curl, где первые 200 в двери сразу же получают поток (и спят), а следующие 800 помещаются в очередь Tomcat / Java, следующие 200 помещаются в очередь в стеке TCP / IP, а экземпляр # 1201 получает ответ «отказано в соединении».

Как только первый набор из 200 запросов будет завершен, Tomcat обработает другой пакет из 200 запросов, 200 соединений в очереди TCP / IP будут перемещены из этой очереди в очередь Tomcat / Java, а через 20 секунд второй набор из 200 запросов будет выполнено. Это будет повторяться до тех пор, пока все 1200 первоначальных запросов не вернут ответ своим клиентам. Только 1 из 1200 запросов будет отклонен.

...