Как правильно настроить работу Server Sent Events (SSE) в Apache + Tomcat?

Вопрос или проблема

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

Оцените материал
Добавить комментарий

Капча загружается...