Назад | Перейти на главную страницу

Apache Tomcat зависает после 300 подключений

У нас есть веб-сервер apache перед Tomcat, размещенный на EC2, тип экземпляра очень большой с памятью 34 ГБ.

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

В часы пик сервер подавляет примерно 300 процессов httpd. ps -ef | grep httpd | туалет -l = 300

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

Я увеличил ограничения на максимальное количество подключений и максимальное количество клиентов как в apache, так и в tomcat. вот детали конфигурации:

// apache

   <IfModule prefork.c>
    StartServers 100
    MinSpareServers 10
    MaxSpareServers 10
    ServerLimit 50000
    MaxClients 50000
    MaxRequestsPerChild 2000
    </IfModule>

//Кот

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="600000"
           redirectPort="8443"
           enableLookups="false" maxThreads="1500"
           compressableMimeType="text/html,text/xml,text/plain,text/css,application/x-javascript,text/vnd.wap.wml,text/vnd.wap.wmlscript,application/xhtml+xml,application/xml-dtd,application/xslt+xml"
           compression="on"/>

//Sysctl.conf

 net.ipv4.tcp_tw_reuse=1
 net.ipv4.tcp_tw_recycle=1
 fs.file-max = 5049800
 vm.min_free_kbytes = 204800
 vm.page-cluster = 20
 vm.swappiness = 90
 net.ipv4.tcp_rfc1337=1
 net.ipv4.tcp_max_orphans = 65536
 net.ipv4.ip_local_port_range = 5000 65000
 net.core.somaxconn = 1024

Я пробовал множество предложений, но тщетно .. как это исправить? Я уверен, что сервер m2xlarge должен обслуживать больше запросов, чем 300, возможно, я ошибаюсь с моей конфигурацией ..

Сервер задыхается только в часы пик и когда есть 300 одновременных запросов, ожидающих ответа веб-службы [с задержкой 300 секунд].

Я просто отслеживал TCP-соединения с помощью netstat

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

Вывод ТОП

 8902  root      25   0 19.6g 3.0g  12m S  3.3  8.8  13:35.77 java
 24907 membase   25   0  753m 634m 2528 S  2.7  1.8 285:18.88 beam.smp
 24999 membase   15   0  266m 121m 3160 S  0.7  0.3  51:30.37 memcached
 27578 apache    15   0  230m 6300 1536 S  0.7  0.0   0:00.03 httpd
 28551 root      15   0 11124 1492  892 R  0.3  0.0   0:00.25 top


 Output of free -m
 total       used       free     shared    buffers    cached
 35007       8470       26536    0          1         61
 8407        26599
 15999       15         15984

 output of iostat
 avg-cpu:  %user   %nice %system %iowait  %steal   %idle
      26.21    0.00    0.48    0.13    0.02   73.15

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda1             14.36         4.77       329.37    9005402  622367592
sdb               0.00         0.00         0.00       1210         48

Также в пиковое время существует около 10-15 тыс. Tcp-подключений к серверу мембазы [локальный]

НЕКОТОРЫЕ ОШИБКИ В ЖУРНАЛЕ MODJK, надеюсь, это проливает свет на проблему ..

[Wed Jul 11 14:39:10.853 2012] [8365:46912560456400] [error]         ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:18.627 2012] [8322:46912560456400] [error] ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:21.358 2012] [8351:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)
[Wed Jul 11 14:39:22.640 2012] [8348:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)

~

Worker.properties
workers.tomcat_home=/usr/local/tomcat/
worker.list=loadbalancer
worker.tom1.port=8009
worker.tom1.host=localhost
worker.tom1.type=ajp13
worker.tom1.socket_keepalive=True
worker.tom1.connection_pool_timeout=600
worker.tom2.port=8109
worker.tom2.host=localhost
worker.tom2.type=ajp13
worker.tom2.socket_keepalive=True
worker.tom2.connection_pool_timeout=600
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tom1,tom2
worker.loadbalancer.sticky_session=True
worker.tom1.lbfactor=1
worker.tom1.socket_timeout=600
worker.tom2.lbfactor=1
worker.tom2.socket_timeout=600

// Решено

Спасибо всем за ваши ценные предложения. Я пропустил настройки maxThreads для коннектора AJP 1.3. Теперь все, кажется, под контролем.

Я бы также начал смотреть даже на базовые серверы, такие как nginx.

Вы увеличили maxThreads в коннекторе AJP 1.3 на порту 8009?

Подумайте о настройке асинхронного прокси-сервера, например nginx или lighttpd перед Apache. Apache обслуживает контент синхронно, поэтому рабочие блокируются до тех пор, пока клиенты не загрузят сгенерированный контент полностью (подробнее Вот). Настройка асинхронного (неблокирующего) прокси обычно значительно улучшает ситуацию (раньше я уменьшал количество одновременно работающих рабочих Apache с 30 до 3-5, используя nginx в качестве внешнего прокси).

Я подозреваю, что ваша проблема в tomcat, а не в apache, из журналов, которые вы все равно показали. Когда вы получаете «ошибку 110» при попытке подключиться обратно к tomcat, это означает, что у вас есть очередь соединений, ожидающих обслуживания, которые больше не могут вписаться в настройку невыполненной работы прослушивания для прослушивающего сокета в tomcat.

From the listen manpage:
   The  backlog  parameter defines the maximum length the queue of pending 
   connections may grow to.  If a connection request arrives with
   the queue full the client may receive an error with an indication
   of ECONNREFUSED or, if the underlying protocol supports  
   retransmission, the request may be ignored so that retries succeed.

Если бы мне пришлось угадывать, я бы заподозрил, что подавляющее большинство HTTP-запросов, когда сервер «задыхается», блокируется в ожидании ответа от tomcat. Бьюсь об заклад, если вы попытаетесь получить какой-то статический контент, который напрямую обслуживается apache (а не проксируется на tomcat), это сработает, даже когда он обычно «задыхается».

К сожалению, я не знаком с tomcat, но есть ли способ вместо этого управлять настройками параллелизма?

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

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

Первым шагом к устранению этой проблемы является включение Apache mod_status и изучая его отчет - пока вы этого не сделаете, вы идете слепо. Это не праведно. ;-)

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

Кроме того, ты точно restart apache, или просто gracefulлы перезагружен Это? :)

Для любого типа корпоративного развертывания prefork MPM - едва ли не худший выбор, который вы можете сделать: он поглощает ресурсы, как никто другой, а перезапуск потоков занимает НАВСЕГДА по сравнению с другими MPM.

По крайней мере, переключитесь на рабочий MPM (apache 2.2 и выше) или, что еще лучше, обновление до текущей стабильной версии 2.4.2 со значением по умолчанию мероприятие MPM.

Оба они легко справятся с тысячами одновременных подключений с очень небольшими накладными расходами.

Я знаю, что это старая история, но у меня есть 2 замечания.

Eсть жестко заданный предел для ServerLimit Директива. http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit вы увидите, что это максимум 20000/200K.

Существует жесткое ограничение ServerLimit 20000, скомпилированного на сервере (для prefork MPM 200000). Это сделано, чтобы избежать неприятных эффектов, вызванных опечатками.

2-й По-видимому, nodybo упомянул, что установка этих 2 в один - это очень плохая идея:

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

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

Я нашел очень хорошую статью, объясняющую это, но - она ​​французская ;-) http://vincent.bernat.im/fr/blog/2014-tcp-time-wait-state-linux.html

очень большой с памятью 34 ГБ.

Большое железо - это не способ масштабировать веб-сервис, вы просто устраняете узкие места. Но даже с таким большим объемом памяти я подозреваю, что 50000 соединений подталкивают систему к тому, на что способна, особенно если:

В часы пик сервер подавляет около 300 процессов httpd.

Было бы полезно, если бы вы объяснили, что вы имеете в виду под «сервером давится».

Также очень странно иметь такой высокий предел для соединений, но очень низкий предел для гистерезиса (мин. / Макс. Резервные серверы).

Хотя предоставленный вами фрагмент ошибок не показывает явного «слишком много открытых файлов», я бы начал с рассмотрения количества открытых файловых дескрипторов и настроек ulimit.

Возможно, у пользователя Apache заканчиваются разрешенные дескрипторы файлов? Вы их вообще не упомянули в своем посте. Сколько файловых дескрипторов в настоящее время может иметь Apache?

Это больше похоже на комментарий, но это невозможно, так как у меня меньше репутации. Возникла точно такая же проблема, как у @john titus.

Сделали разъем AJP MaxThreads близко к нашему пределу потока Apache, чтобы решить проблему.

Для наблюдения за этим мы искали SYN_SENT Справка по статусу порта netstat с помощью команды netstat на нашем порту AJP.

netstat -an | grep :8102 | grep SYN_SENT | wc -l

Это снизилось до 0, которое всегда было большим числом до ограничения MaxThread, установленного для AJP Connector.