Предварительный просмотр
Мой первый путь, пересекшийся с проблемой сломанной трубы, произошел, когда я просматривал журналы программного обеспечения, над которым работал.
Стек для программного обеспечения был:
- Java EE 7 с JAX-RS
- Java 8
- Wildfly 10.1 в качестве сервера приложений
- Nginx использовался в качестве обратного прокси-сервера и балансировщика нагрузки.
Я мог видеть следующие следы, заполняющие журнал:
java.lang.RuntimeException: org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
Я игнорировал это пару раз ранее, думая, что это не создало никакого хаоса на рабочем сервере, и не был совсем уверен, как это было сгенерировано и как с этим справиться или полностью предотвратить.
Что именно такое Сломанная труба?
Проще говоря, сломанный канал означает, что машина пытается считывать или записывать данные из/в канал, в то время как машина на другом конце канала умерла или была прекращена. Теперь, поскольку соединение закрыто, необходимо установить новое соединение для дальнейшей передачи данных, в противном случае передача данных прекращается.
Как это происходит?
Одной из наиболее распространенных причин этой проблемы является то, что клиент закрывает открытое соединение во время выполнения какого-либо действия (например, загрузки страницы или загрузки вложения). Это также происходит при принудительном закрытии определенных подключений при использовании прокси-сервера/балансировщика нагрузки, такого как Nginx (например, закрытие веб-браузера или даже просто отмена загрузки) или при медленном соединении.
Простой сценарий: браузер запрашивает ресурс у сервера, и в ответ сервер возвращает ответ браузеру. Что делать, если пользователь закрывает браузер, когда сервер отправляет ответ браузеру? Соединение между сервером и браузером неожиданно закрывается. Затем это приводит к повреждению трубы, и исключение называется как java.io . Исключение IOException: Сломанный канал в Java.
Это также может произойти со всем, что прерывает соединение между клиентом и сервером, включая проблемы с производительностью или даже перебои в работе сети.
Не каждое исключение из неработающего канала является ошибкой разработчика
Возможные факторы, приводящие к этому исключению:
Количество конечных пользователей Поскольку одной из основных причин обрыва канала является поведение пользователя (неожиданное закрытие активного сеанса браузера до того, как сервер сможет завершить отправку ответа), увеличение числа конечных пользователей увеличивает вероятность обрыва канала.
Большая нагрузка на отклик Интенсивный ответ от сервера требует значительного времени для передачи на сторону клиента, и этот огромный промежуток времени может иметь место в случае неработающего канала.
Тайм-аут сервера Если веб-сервер не смог получить ответ от службы за определенное время, равное значению тайм-аута, установленному на сервере, он закрывает соединение с клиентской частью, возвращая 503: Тайм-аут шлюза и, следовательно, вызывая прерывание канала.
Является ли Исключение Сломанной трубы красным сигналом?
Справедливости ради, это не красный сигнал, потому что в значительной степени это вызвано нормальным поведением пользователя, и всегда есть вероятность отключения служб из-за каких-то сбоев. Но, если сервер работает с относительно большим количеством пользовательских запросов одновременно, то не только прерывистый канал, но и любое исключение, по-видимому, создают проблему.
В моем случае, из-за высокого сетевого трафика, журналы были заполнены неработающим исключением канала. Поскольку запись в файл (операция ввода-вывода) является одной из дорогостоящих операций, выполняемых сервером, представьте, что сервер заполнен исключением, связанным с прерывистым каналом, и объем ресурсов, который сервер должен использовать, чтобы записать это исключение stacktrace в файл журнала. Это привело к медленному реагированию сервера и сделало его вялым. В этот момент я понял, ДА, ИСКЛЮЧЕНИЕ ИЗ РАЗОРВАННОЙ ТРУБЫ – ЭТО КРАСНЫЙ СИГНАЛ при масштабировании до большого трафика.
Проблемы, связанные с обработкой или удалением сломанной трубы
Система использовала Wildfly 10.1 в качестве сервера приложений и была написана на Java EE 7. Обработка этого сценария не была для меня легкой прогулкой, поскольку:
Репликация этого исключения в локальной среде или среде контроля качества требует, чтобы все планеты были правильно выровнены (просто шучу), но да, это слишком сложно.
Обработка исключений в Java проста, если исключение перехвачено внутри блока catch. Природа необработанного исключения: java.io . Исключение IOException: Сломанный канал таков, что он извлекается из контейнера Wildfly и выходит из системы в stacktrace вместо того, чтобы быть захваченным в блоке catch. Теперь представьте, что вам приходится иметь дело с исключением, которое не может быть перехвачено из кода. Черт возьми!!!!
Вы никогда не узнаете, какой запрос вызвал проблему, так как сервер получал большое количество запросов, и любой из них мог стать причиной исключения. Добавление журналов ко всем конечным точкам rest вместе с конечными точками сокетов невозможно.
Фиксация java.io . Исключение IOException: Сломанная труба
Наконец, после стольких вырванных из контекста разговоров, вот и основной раздел (надеюсь, его стоит подождать).
Есть два способа удалить исключение из системы::
- Исследуйте первопричину исключения и устраните ее.
- Обработайте исключение изящно, с правильным ведением журнала или каким-либо действием.
Устранение первопричин
Просить пользователя не закрывать соединение неожиданно Ради бога, это невозможно сделать
Снижение нагрузки на ответы api Это каким-то образом достижимо, но в устаревшей системе, работающей с большим объемом данных, переписывание всей логики так, чтобы ответы api не были тяжелыми, также неосуществимо во всех случаях.
Увеличивающийся тайм-аут сервера Nginx имеет переменную с именем proxy_read_timeout который имеет значение по умолчанию 60 секунд, увеличение этого значения также сведет к минимуму вероятность разрыва канала.
Даже после устранения точной первопричины, которую саму по себе трудно обнаружить в данном случае, мы не можем полностью исключить существование сломанной трубы. Можем ли мы?
Следовательно, следующее решение – изящно обращаться со сломанной трубой.
Обработка java.io . Исключение IOException: Сломанная труба
- Подавить журнал из самого blogger Если вы используете log4j в качестве менеджера журналов, добавление следующей конфигурации в log4j.properties поможет избавиться от исключения, заполняющего журналы из-за сломанного канала.
log4j.logger.org.apache.catalina.connector.ClientAbortException = ERROR, console, cloudAppender log4j.additivity.org.apache.catalina.connector.ClientAbortException = false
- Обновление Resteasy в Wildfly Мы использовали Resteasy реализацию JAX-RS для реализации REST в Java, а Rest easy v3.0.19 поставляется в комплекте с Wildfly 10.1. В надежде найти некоторые исправления в самом resteasy я начал копаться в примечаниях к выпуску Resteasy и обнаружил, что после Resteasy-Client v3.1.1 Необработанное исключение: java.io . Исключение IOException может быть перехвачено из кода, в отличие от контейнера, отображающего его непосредственно в трассировке журнала. Следовательно, обновление версии Resteasy Client позволяет нам обрабатывать исключения с помощью глобального обработчика исключений (описано в более позднем пункте).
Шаги по обновлению Resteasy в Wildfly
Найдите расположение банок дистрибутива Resteasy: Расположение банок дистрибутива Resteasy находится внутри: WILDFLY_HOME/modules/system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main , а имя файла: resteasy-jaxrs-3.0.19.Final.jar
Загрузите zip-файл целевой версии resteasy (3.1.1 и выше) с Resteasy downloads
Распакуйте файл во временную директорию. В нем есть два других zip-файла: resteasy-jboss-modules-3.1.1.Final-mavenized.zip & resteasy-jboss-modules-3.1.1.Final.zip
Распакуйте оба zip-файла по адресу: WILDFLY_HOME/модули/система/слои/база
Обновите версию зависимостей resteasy в pom.xml
org.jboss.resteasy resteasy-jaxrs 3.1.1.Final provided
- Использовать Глобальный обработчик исключений Я также добавил GenericExceptionMapper из самого кода java, чтобы перехватывать и обрабатывать неработающий канал.
Мой последний подход
Хотя я собрал несколько методов для решения этой проблемы, ниже приведены вещи, которые я на самом деле реализовал:
- Обновите Wildfly до версии 11.0, так как он автоматически поставляется с Resteasy v3.1.1 (версия, которую я точно хотел) в комплекте с ним.
- Обрабатывать исключение с помощью глобального обработчика исключений
и с этим проблема сломанной трубы теперь существует только в старых архивах журналов 😎 😎 .
Прощальные слова
Это мой первый блог, да, это немного длинновато, но я рассказывал о том, как я на самом деле подошел к проблеме и исправил ее. Не стесняйтесь оставлять отзывы в разделе комментариев и следите за этим пространством, чтобы в будущем было больше блогов о разработке.
Кроме того, немного саморекламы в конце 😉 . Свяжитесь со мной по адресу Twitter & LinkedIn
Рекомендации
Оригинал: “https://dev.to/bishwapoudel/how-i-fixed-java-io-ioexception-broken-pipe-in-java-wildfly-10-1-86k”