Вопрос или проблема
Я использую Apache 2.4.10 на Debian в качестве фронтального веб-сервера с экземпляром Tomcat 8.0.28 в бэкенде. Их цель – обслуживать стандартные JSP-страницы, некоторые из которых динамически обновляются.
Мои веб-приложения работают нормально, за исключением случаев, когда дело доходит до рассылки уведомлений через SSE. Через несколько минут Tomcat начинает сбоить, перестает обслуживать страницы (HTTP 500) и иногда смешивает содержимое SSE с обычным HTML-потоком.
Важно отметить: в среде разработки всё, что связано с SSE, работает безукоризненно, когда мы запускаем Tomcat без Apache, под Windows 7/10. Эта деталь и то, что я читаю в логах, убеждают меня в том, что проблема кроется в Apache.
Может ли Apache обрабатывать запросы SSE?
Если да, какую конфигурацию мне следует применить?
Большое спасибо за вашу помощь.
Дополнительная информация:
Конфигурация Apache:
- Apache 2.4.10 (Debian 64-bit) OpenSSL/1.0.1k
- mpm-event с mod_headers, mod_ssl, mod_rewrite, mod_proxy, mod_proxy_http
- Интеграция с Tomcat осуществляется с помощью mod_proxy_ajp
Конфигурация веб-приложений:
- Tomcat 8.0.28 с версией Java "1.7.0_79" (OpenJDK 64-бит)
- Коннектор настроен на использование протокола AJP/1.3
- Сервер SSE основан на Jersey 2.5.1
- Tomcat размещает несколько веб-приложений, все они маршрутизируются через директиву ProxyPass (например, ProxyPass /webapp1 ajp://10.10.12.2:8015/webapp1, ProxyPass /webapp2 ajp://10.10.12.2:8015/webapp2 и так далее).
Логи Tomcat:
[list] 07-Apr-2019 19:55:19.580 INFO [pool-13-thread-1] org.apache.coyote.AbstractProcessor.setErrorState An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.io.IOException: Разрыв соединения (pipe)
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
[...]
at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
[...]
at org.apache.coyote.ajp.AbstractAjpProcessor.action(AbstractAjpProcessor.java:410)
[...]
at org.glassfish.jersey.server.Broadcaster.broadcast(Broadcaster.java:150)
[...]
at SAR.DTS.Base.b.o.run(ThreadMajRappels.java:58)
[...]
at java.lang.Thread.run(Thread.java:745)[/list]
07-Apr-2019 20:10:05.344 INFO [ajp-nio-8015-exec-10] org.apache.catalina.connector.CoyoteAdapter.checkRecycled Encountered a non-recycled response and recycled it forcedly.
org.apache.catalina.connector.CoyoteAdapter$RecycleRequiredException
at org.apache.catalina.connector.CoyoteAdapter.checkRecycled(CoyoteAdapter.java:710)
at org.apache.coyote.ajp.AbstractAjpProcessor.recycle(AbstractAjpProcessor.java:943)
at org.apache.coyote.ajp.AjpNioProtocol$AjpConnectionHandler.release(AjpNioProtocol.java:163)
Логи Apache:
[Sun Apr 07 20:05:22.338619 2019] [proxy_ajp:error] [pid 6573] [client xx.xx.x.xxx:61445] AH00893: dialog to 10.10.12.2:8015 (10.10.12.2) failed, referer: http://yy.yy.yy.yyy/webapp1
[Sun Apr 07 20:10:05.344774 2019] [proxy_ajp:error] [pid 6573] [client xx.xx.x.xxx:62693] AH00992: ajp_read_header: ajp_ilink_receive failed, referer: http://yy.yy.yy.yyy/webapp1
[Sun Apr 07 20:10:05.344783 2019] [proxy_ajp:error] [pid 6573] (120006)APR не понимает этот код ошибки: [client xx.xx.x.xxx:62693] AH00878: read response failed from 10.10.12.2:8015 (10.10.12.2), referer: http://yy.yy.yy.yyy/webapp1
[Sun Apr 07 20:10:05.344745 2019] [proxy_ajp:error] [pid 6573] (104)Сброс соединения со стороны удаленного хоста: AH01030: ajp_ilink_receive() не может получить заголовок
Да, Apache может!
Я нашел способ заставить SSE работать в Apache + Tomcat, заменив AJP-коннектор на очень простой HTTP:
В конфигурации Apache:
# Это утверждение предотвращает перенаправление Apache на локальный URL.
# Странно, но это не нужно при использовании AJP-коннектора...
ProxyPreserveHost On
ProxyPass /webapp1 http://10.10.12.2:8016/webapp1
И в конфигурации Tomcat:
<Connector
port="8016"
protocol="org.apache.coyote.http11.Http11NioProtocol"
proxyPort="80" />
Не знаю, является ли это верным решением первоначальной проблемы, но это приближает меня к цели…
На данный момент я попробую 1) найти (если он есть) правильный конфиг для AJP и 2) заставить HTTP-конфиг работать с SSL и SSE.
Ответ или решение
Настройка Server Sent Events (SSE) в связке Apache и Tomcat может стать сложной задачей, но обращая внимание на детали конфигурации, можно обеспечить стабильно работающее решение. Ваша текущая установка, где Apache 2.4.10 на Debian служит фронтальным веб-сервером, а Tomcat 8.0.28 обрабатывает backend, уже почти настроена, но сталкивается с проблемами при попытке транслировать уведомления с помощью SSE.
Важно отметить, что ваша проблема, скорее всего, связана с использованием AJP-коннектора. В вашей конфигурации Tomcat и Apache взаимодействуют через AJP-протокол (Apache JServ Protocol), который иногда может неправильно обрабатывать долгоживущие соединения, такие как SSE.
Для успешной настройки SSE предлагается переход на использование HTTP-коннектора, что вы уже частично реализовали. Ниже приведены основные шаги, которые помогут вам надежно настроить SSE:
1. Конфигурация Apache
Для начала, измените конфигурацию вашего Apache, чтобы использовать HTTP-коннектор вместо AJP:
ProxyPreserveHost On
ProxyPass /webapp1 http://10.10.12.2:8016/webapp1
ProxyPassReverse /webapp1 http://10.10.12.2:8016/webapp1
- ProxyPreserveHost On: эта директива сохраняет заголовок хоста клиента в запросах, которые Apache направляет на Tomcat, что может быть важно для правильного функционирования приложений.
2. Конфигурация Tomcat
Теперь измените конфигурацию Tomcat, добавив HTTP-коннектор:
<Connector port="8016" protocol="org.apache.coyote.http11.Http11NioProtocol" proxyPort="80" />
- org.apache.coyote.http11.Http11NioProtocol: этот протокол поддерживает асинхронные операции ввода-вывода, что делает его подходящим для сценариев с длительными соединениями, такими как SSE.
3. Безопасность и SSL
Если вам необходимо использовать SSL, Apache может обрабатывать SSL и шифровать соединения между клиентом и сервером. Используйте mod_ssl в Apache для настройки HTTPS:
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /path/to/certificate.crt
SSLCertificateKeyFile /path/to/private.key
ProxyPreserveHost On
ProxyPass /webapp1 http://10.10.12.2:8016/webapp1
ProxyPassReverse /webapp1 http://10.10.12.2:8016/webapp1
</VirtualHost>
4. Тестирование и мониторинг
После изменения конфигураций проведите тестирование для проверки функциональности SSE. Обратите внимание на логи Apache и Tomcat для своевременного обнаружения и устранения возможных ошибок. Мониторинг поможет выявить проблемы на ранней стадии и предотвратить повторные случаи.
Эти шаги должны помочь в эффективном развертывании SSE, обеспечивая устойчивость и надежность. помнить, что каждая установленная конфигурация специфична для конкретного контекста, поэтому тестирование всегда необходимо.