it-swarm-ru.tech

У Apache + Tomcat проблемы со связью. Непонятные сообщения об ошибках. Преодоление веб-сайтов, размещенных под Tomcat

Настройка:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache пересылает запросы с использованием AJP.

Проблема:
Через определенный промежуток времени (вообще не постоянный, может быть между часом или двумя, или одним или несколькими днями) Tomcat будет падать. Либо он перестает отвечать на запросы, либо выдает универсальный "Сервис временно недоступен".

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

На первом сервере, когда возникает проблема, все потоки медленно начинают работать, пока не достигнут предела (MaxThreads 200). В этот момент сервер больше не отвечает (и после долгого периода времени появляется страница недоступной службы).

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

За исключением упоминания о проблеме MaxThreads, журналы Tomcat не указывают на какие-либо конкретные проблемы, которые могут быть причиной этого.

Однако в журналах Apache мы видим случайные сообщения, ссылающиеся на AJP. Вот образец случайного сообщения, которое мы видим (без определенного порядка):

[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)

Еще одна странная вещь, которую мы заметили на сервере с более высоким трафиком, заключается в том, что непосредственно перед тем, как проблема начинает возникать, запросы к базе данных занимают намного больше времени, чем раньше (2000-5000 мс по сравнению с обычно 5-50 мс). Это длится всего 2-4 секунды до появления сообщения MaxThreads. Я предполагаю, что это результат того, что сервер внезапно столкнулся со слишком большим объемом данных/трафика/потоков.

Справочная информация:
Эти два сервера работали без проблем в течение достаточно долгого времени. Системы были фактически настроены каждая с использованием двух сетевых карт в течение этого времени. Они разделили внутренний и внешний трафик. После обновления сети мы переместили эти серверы на отдельные сетевые карты (это было рекомендовано нам по соображениям безопасности/простоты). После этого изменения серверы начали испытывать эти проблемы.

Разрешение:
Очевидным решением было бы вернуться к настройке двух сетевых карт. Проблемы с этим состоят в том, что это может вызвать некоторые сложности с настройкой сети, и кажется, что игнорирование проблемы. Мы бы предпочли попробовать запустить его на одной установке NIC.

Поиск различных сообщений об ошибках не дал ничего полезного (старых решений или не относящихся к нашей проблеме).

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

Мы не уверены, где искать, чтобы диагностировать проблему дальше. Мы все еще цепляемся за соломинку, в чем может быть проблема:

1) Настройка с AJP и Tomcat неверна или устарела (т.е. известны ошибки?)
2) Настройка сети (две NIC против одной NIC) вызывает путаницу или проблемы с пропускной способностью.
3) Сами веб-сайты (нет общего кода, не используются платформы, просто базовый Java код с сервлетами и JSP)

Обновление 1:
Следуя полезному совету Дэвида Пашли, я выполнил трассировку стека/дамп потока во время проблемы. Я обнаружил, что все 200 потоков находились в одном из следующих состояний:

"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at  Oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.Java:988)
- waiting to lock <0x7e3455a0> (a Oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at Oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.Java:268)
- waiting to lock <0x7e3455a0> (a Oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

Любопытно, что только один поток из всех 200 потоков находился в этом состоянии:

"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at Java.net.SocketInputStream.socketRead0(Native Method)
at Java.net.SocketInputStream.read(SocketInputStream.Java:129)
at Oracle.net.ns.Packet.receive(Unknown Source)
at Oracle.net.ns.DataPacket.receive(Unknown Source)
at Oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at Oracle.net.ns.NetInputStream.read(Unknown Source)
at Oracle.net.ns.NetInputStream.read(Unknown Source)
at Oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]

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

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

22
Jordy Boom

Оказывается, что в этой версии (класс 12 - довольно старая) драйвера Oracle были различные ошибки, которые вызывали взаимоблокировку (как видно из состояния TP-Processor2, указанного выше). Он не стал активным, пока мы не переключились на новую среду. Обновление до последней версии (ojdbc14) решило проблему на основном сервере.

9
Jordy Boom

Из описания я бы предположил, что проблема может быть связана с тем, что запросы к базе данных занимают слишком много времени. Если запросы занимают больше времени, запрос будет длиться дольше, и поэтому у вас будет больше запущенных одновременно. Как видите, у вас закончились потоки Tomcat. Когда вы решите проблему с базой данных, все будет в порядке.

  • Получить трассировку стека, либо с помощью jstack, либо с помощью kill -3 $ process_id. Посмотрите, что ваши темы делают, когда он умирает. Если они все ждут в базе данных, это хороший указатель на мою теорию. Возможно, все они ждут в каком-то замке.
  • Установите LambdaProbe. Это неоценимо для выяснения того, что делает ваш Tomcat.
  • Обновите свой Tomcat. 5.5.8 невероятно стар. Я думаю, что они сейчас на 5.5.27.
6
David Pashley

Добавьте connectionTimeout и keepAliveTimeout к вашему коннектору AJP, расположенному в /etc/Tomcat7/server.xml.

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

Информация о соединителе AJP по адресу https://Tomcat.Apache.org/Tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Количество миллисекунд, которые этот Соединитель будет ожидать после принятия соединения, чтобы была представлена ​​строка URI запроса. Значение по умолчанию для соединителей протокола AJP равно -1 (то есть бесконечно).

  • keepAliveTimeout = Количество миллисекунд, которое этот Соединитель будет ожидать другого запроса AJP перед закрытием соединения. Значением по умолчанию является использование значения, установленного для атрибута connectionTimeout.

Если значения connectionTimeout и keepAliveTimeout не определены, то соединения AJP будут поддерживаться бесконечно долго. Причиняет много потоков, максимальное количество потоков по умолчанию составляет 200.

Я рекомендую установить psi-probe - расширенный менеджер и монитор для Apache Tomcat, разветвленный от Lambda Probe. https://code.google.com/p/psi-probe/

5
paalfe

Из-за того, как работает AJP, постоянные соединения между Apache (использующие mod_proxy_ajp или mod_jk) могут быть безопасно закрыты только клиентом. В этом случае клиент - это рабочий Apache, который открывается, а затем удерживает соединение с Tomcat для срок действия рабочего процесса.

Из-за этого поведения у вас не может быть больше рабочих Apache, чем рабочих потоков Tomcat. Это приведет к тому, что дополнительные работники http не смогут подключиться к Tomcat (так как очередь приема заполнена) и пометит ваш бэкэнд как DOWN!

4
Dave Cheney

У меня были лучшие результаты с mod_proxy вместо mod_ajp с точки зрения стабильности, поэтому попробуйте это решение. Он неинвазивен - в лучшем случае решит проблему, а в худшем исключит mod_ajp.

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

2
Robert Munteanu

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

Если у вас заканчивается ОЗУ, вам может потребоваться выключить Apache MaxClients и ​​увеличить ListenBacklog.

Кстати, спасибо, что сделали ваш вопрос так хорошо организованным и полным.

1
chaos

У меня были подобные ошибки журнала в среде Redhat с proxy_ajp и Tomcat. Решено обновлением пакета httpd:

yum update httpd

от:

  • hTTPD-разви-2.2.3-43.el5_5.3.x86_64
  • hTTPD-2.2.3-43.el5_5.3.x86_64

чтобы:

  • hTTPD-2.2.3-45.el5_6.3.x86_64
  • hTTPD-разви-2.2.3-45.el5_6.3.x86_64

Затем перезапустил Apache, после чего перезапустил Tomcat.

Это исправило это для меня!

1
Bass