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

22

Установка:
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 в этом потоке заставляет все остальные потоки ждать его завершения. По какой-то причине он должен застрять в этом состоянии чтения (сервер никогда не восстанавливается самостоятельно, он требует перезагрузки).

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

Джорди Бум
источник
Прежде всего, это потрясающе написанный вопрос. Фантастическая работа над деталями! Во-вторых, вы используете proxy_ajp или mod_jk для подключения серверов Apache и Tomcat?
Офидиан
Я использую proxy_ajp для соединения двух.
Джорди Бум
Делайте стресс-тесты, используя осаду, joedog.org/siege-home .
Paalfe

Ответы:

9

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

Джорди Бум
источник
Это привело меня к моему правильному решению: у меня был замок в БД-рядной ... и никогда не получал каких - либо исключений в App-сервера
cljk
6

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

  • Получить трассировку стека, либо с помощью jstack, либо с помощью kill -3 $ process_id. Посмотрите, что ваши темы делают, когда он умирает. Если они все ждут в базе данных, это хороший указатель на мою теорию. Возможно, все они ждут в каком-то замке.
  • Установите LambdaProbe. Это неоценимо для выяснения того, что делает ваш кот.
  • Обнови свой кот. 5.5.8 невероятно стар. Я думаю, что они сейчас на 5.5.27.
Дэвид Пашли
источник
Дэвид, я обновил вопрос (см. Обновление 1), добавив новые результаты, основанные на предложении трассировки дампа / стека потока.
Джорди Бум
Я бы предположил, что ваш пул соединений с базой данных слишком мал по сравнению с вашим максимальным значением соединения tomcat. Похоже, что большинство потоков ожидает подключения к базе данных.
Дэвид Пашли
Единственная причина, по которой так много потоков, заключается в том, что обычно используемые потоки остаются в ожидании того, что один поток пытается прочитать из сокета. Количество соединений с БД, используемых в любое время, колеблется от 1 до 3. Больше никогда не требуется больше.
Джорди Бум
5

Добавьте 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/

paalfe
источник
4

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

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

Дейв Чейни
источник
1
Извините за комментарий после всех этих лет, но разве это не может быть гарантировано установкой max-flag в конфигурации ProxyPass на количество MaxThreads контейнера сервлета?
Хорст Гутман
2

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

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

Роберт Мунтяну
источник
У меня сложилось впечатление, что у mod_proxy есть некоторые проблемы с масштабируемостью, хотя его проще подключить. Похоже, что фонд Apache рекомендует mod_jk ( wiki.apache.org/tomcat/FAQ/Connectors#Q2 )
Ophidian
Это не обеспечивает липкую сессию, правда. Но кроме этого у меня никогда не было проблем с этим.
Роберт Мунтяну
1

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

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

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

хаос
источник
Когда я наблюдаю «верх», пока это происходит, использование памяти остается достаточно постоянным. По крайней мере, там нет шипов. Там только краткий момент высокой загрузки процессора.
Джорди Бум
1

У меня были подобные ошибки журнала в среде 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.

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

бас
источник