
Мы внезапно наблюдаем прерывистую, но очень частую ошибку при отправке файлов на сервлет Tomcat по https через обратный прокси-сервер Apache. Ошибка, похоже, возникает только при отправке файлов размером 20 МБ или более (видео). Мы не наблюдали проблемы с файлами меньшего размера от 2 до 5 МБ (JPEG).
Ошибка возникает на двух из пяти серверов, на которых мы ее опробовали.
На стороне сервера соединения, т.е. сервлета Tomcat, созданного с использованием Jersey, мы получаем:
java.net.SocketException: Connection reset
Сервер Apache на той же машине, действующий как обратный прокси-сервер, выдает следующее сообщение об ошибке:
[Thu May 15 17:08:58 2014] [error] proxy: pass request body failed to 127.0.0.1:8080 (localhost) from 192.168.16.xx ()
Установка уровня ведения журнала сервера Apache на отладку и воспроизведение проблемы не дает никакой дополнительной информации — мы по-прежнему получаем то же самое сообщение об ошибке без каких-либо связанных сообщений.
Немного реже мы не получаем исключения на стороне Tomcat, но проверка количества переданных байтов по заголовку Content-Length показывает, что не все прошло. Ошибка в Apache Server во втором сценарии та же, что и в первом "proxy: pass request body failed..."
Версия Apache Server — 2.2.15.29 на одном сервере и 2.2.15.30 на другом, во всех случаях работающем под CentOS 6.2. Правила обратного прокси-сервера настраиваются следующим образом:
<IfModule mod_proxy.c>
ProxyRequests Off
# Case Manager Tomcat web service
ProxyPass /casemanager http://localhost:8080/casemanager
ProxyPassReverse /casemanager http://localhost:8080/casemanager
# Matcher images directories
ProxyPass /matcher-images http://x.x.x.108:80/matcher-images
</IfModule>
Обратите внимание, что прокси-сервер работает только по протоколу http, а не https.
Мы используем самоподписанные сертификаты для конфигурации SSL. Версия OpenSSL — 1.0.1e-fips на одном из неисправных серверов и 1.0.0-fips на другом.
На стороне Tomcat мы используем версию 7.0.26 и Jersey 1.8.
Сомневаюсь, что это имеет значение, но соединение браузера, из которого исходит POST, — это Firefox 27 или Chrome 34.
В одном случае наш сервлет был недавно обновлен, хотя код для обработки загрузки файлов не менялся в последнее время. На другом сервере, где возникла проблема, мы запускаем сборку сервлета, созданную несколько месяцев назад. Фактически, на этой второй машине мы не знаем о каких-либо изменениях кода или конфигурации за последние несколько месяцев — она простаивала с середины февраля до сегодняшнего дня.
Что мне делать дальше, чтобы устранить эту проблему? Где мне следует искать?
-- Обновлять --
Дальнейшее тестирование показывает, что соединение иногда обрывается, даже если я обхожу Apache Server и отправляю POST напрямую в Tomcat. Так что, похоже, это вообще не проблема прокси.
-- Дальнейшие обновления --
Мы периодически видим проблемы при копировании тех же больших файлов через scp. Похоже, что основная проблема — это брандмауэр между нашей офисной/разрабатывающей подсетью и производственной/промежуточной сетью. Сообщение об ошибке при сбое копирования scp — «Broken pipe».
Вот трассировка стека сервлета при обрыве соединения:
2014-05-16 13:20:44,566 [http-bio-8080-exec-7] ОШИБКА com.objectvideo.wx.casemanager.service.resources.QueryFileService [null] - Не удалось загрузить файл(ы). javax.ws.rs.WebApplicationException: java.net.SocketException: Сброс соединения в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:342) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadFile(QueryFileService.java:607) в sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke(Method.java:606) в com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60) в com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205) в com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75) в com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288) в com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108) в com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147) в com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84) в com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469) в com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400) в com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349) в com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339) в com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416) в com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537) в com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699) в javax.servlet.http.HttpServlet.service(HttpServlet.java:722) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) в org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224) в org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) в org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) в org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) в org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) в org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) в org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) в org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) в org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987) в org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) в org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) в java.lang.Thread.run(Thread.java:724) Причина: java.net.SocketException: Сброс соединения в java.net.SocketInputStream.read(SocketInputStream.java:189) в java.net.SocketInputStream.read(SocketInputStream.java:121) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501) в org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) в org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) в org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) в org.apache.coyote.Request.doRead(Request.java:422) в org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) в org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) в org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) в org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1719) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1696) в org.apache.commons.io.IOUtils.copy(IOUtils.java:1671) в org.apache.commons.io.FileUtils.copyInputStreamToFile(FileUtils.java:1444) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.writeTempFile(QueryFileService.java:535) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:320) ... еще 35process(AbstractHttp11Processor.java:987) в org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) в org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) в java.lang.Thread.run(Thread.java:724) Причина: java.net.SocketException: Сброс соединения в java.net.SocketInputStream.read(SocketInputStream.java:189) в java.net.SocketInputStream.read(SocketInputStream.java:121) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501) в org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) в org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) в org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) в org.apache.coyote.Request.doRead(Request.java:422) в org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) в org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) в org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) в org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1719) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1696) в org.apache.commons.io.IOUtils.copy(IOUtils.java:1671) в org.apache.commons.io.FileUtils.copyInputStreamToFile(FileUtils.java:1444) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.writeTempFile(QueryFileService.java:535) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:320) ... еще 35process(AbstractHttp11Processor.java:987) в org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) в org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) в java.lang.Thread.run(Thread.java:724) Причина: java.net.SocketException: Сброс соединения в java.net.SocketInputStream.read(SocketInputStream.java:189) в java.net.SocketInputStream.read(SocketInputStream.java:121) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532) в org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501) в org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) в org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) в org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) в org.apache.coyote.Request.doRead(Request.java:422) в org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) в org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) в org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) в org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1719) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1696) в org.apache.commons.io.IOUtils.copy(IOUtils.java:1671) в org.apache.commons.io.FileUtils.copyInputStreamToFile(FileUtils.java:1444) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.writeTempFile(QueryFileService.java:535) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:320) ... еще 35fill(InternalInputBuffer.java:501) в org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) в org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) в org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) в org.apache.coyote.Request.doRead(Request.java:422) в org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) в org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) в org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) в org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1719) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1696) в org.apache.commons.io.IOUtils.copy(IOUtils.java:1671) в org.apache.commons.io.FileUtils.copyInputStreamToFile(FileUtils.java:1444) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.writeTempFile(QueryFileService.java:535) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:320) ... еще 35fill(InternalInputBuffer.java:501) в org.apache.coyote.http11.InternalInputBuffer$InputStreamInputBuffer.doRead(InternalInputBuffer.java:563) в org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:118) в org.apache.coyote.http11.AbstractInputBuffer.doRead(AbstractInputBuffer.java:326) в org.apache.coyote.Request.doRead(Request.java:422) в org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290) в org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431) в org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315) в org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:167) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1719) в org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1696) в org.apache.commons.io.IOUtils.copy(IOUtils.java:1671) в org.apache.commons.io.FileUtils.copyInputStreamToFile(FileUtils.java:1444) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.writeTempFile(QueryFileService.java:535) в com.objectvideo.wx.casemanager.service.resources.QueryFileService.uploadRawFile(QueryFileService.java:320) ... еще 35
решение1
Попробуйте добавить keepalive=on
к своим ProxyPass
директивам.
Это может потребоваться KeepAlive
также on
на глобальном сервере Apache.