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

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. Я предполагаю, что это результат того, что сервер внезапно столкнулся со слишком большим объемом данных / трафика / потоков.

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

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

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

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

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

1) Настройка с AJP и Tomcat неверна или устарела (т.е. известные ошибки?)
2) Настройка сети (два сетевых адаптера против одного сетевого адаптера) вызывает путаницу или проблемы с пропускной способностью.
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 в этом потоке заставляет все другие потоки ждать его завершения. По какой-то причине он должен застрять в этом состоянии чтения (сервер никогда не восстанавливается самостоятельно, требуется перезапуск).

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

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

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

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

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

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

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

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

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

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

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

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

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

yum update httpd

из:

  • httpd-devel-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-devel-2.2.3-45.el5_6.3.x86_64

Затем перезапустили apache, а затем перезапустили Tomcat.

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