
Apache Server リバース プロキシ経由で https 経由で Tomcat サーブレットにファイルを POST しているときに、突然、断続的ではあるが非常に頻繁にエラーが発生するようになりました。このエラーは、20 MB 以上のファイル (ビデオ) を POST しているときにのみ発生するようです。2 ~ 5 MB の小さいファイル (JPEG) では、この問題は発生していません。
エラーは、試した 5 台のサーバーのうち 2 台で発生します。
接続のサーバー側、つまり Jersey を使用して構築された Tomcat サーブレットでは、次のようになります。
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 ヘッダーに対して転送されたバイト数を確認すると、すべてが通過したわけではないことがわかります。この 2 番目のシナリオでの Apache サーバーのエラーは、最初の「プロキシ: リクエスト本文のパスに失敗しました...」と同じです。
Apache サーバーのバージョンは、1 台のサーバーでは 2.2.15.29、もう 1 台のサーバーでは 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>
プロキシ パススルーは https ではなく http を経由することに注意してください。
SSL 構成には自己署名証明書を使用しています。障害が発生したサーバーの 1 つでは OpenSSL バージョンは 1.0.1e-fips で、もう 1 つでは 1.0.0-fips です。
Tomcat 側では、7.0.26 を実行しており、Jersey 1.8 を使用しています。
重要ではないと思いますが、POST の発信元のブラウザ接続は、Firefox 27 または Chrome 34 のいずれかです。
あるケースでは、ファイルのアップロードを処理するコードは最近変更されていないものの、サーブレットは最近更新されました。問題が発生しているもう一方のサーバーでは、数か月前にビルドされたサーブレットを実行しています。実際、その 2 台目のマシンでは、過去数か月間にコードや構成が変更されたことは認識されておらず、2 月中旬から今日までアイドル状態のままでした。
この問題を解決するには、次に何をすればよいですか? どこを確認すればよいですか?
- アップデート -
さらにテストしてみると、Apache サーバーをバイパスして Tomcat に直接 POST した場合でも、接続が切断されることがあることがわかりました。したがって、これはプロキシの問題ではないようです。
-- 今後の更新 --
scp 経由で同じ大きなファイルをコピーするときに、断続的に問題が発生します。根本的な問題は、オフィス/開発サブネットと実稼働/ステージング ネットワーク間のファイアウォールにあるようです。scp コピーが失敗したときのエラー メッセージは、「パイプが壊れています」です。
接続が切断されたときのサーブレットからのスタック トレースは次のとおりです。
2014-05-16 13:20:44,566 [http-bio-8080-exec-7] ERROR 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(不明なソース)、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) ... 35 件以上process(AbstractHttp11Processor.java:987) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724) 原因: java.net.SocketException: 接続がリセットされました at java.net.SocketInputStream.read(SocketInputStream.java:189) at 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) ... 35 件以上process(AbstractHttp11Processor.java:987) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724) 原因: java.net.SocketException: 接続がリセットされました at java.net.SocketInputStream.read(SocketInputStream.java:189) at 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) ... 35 件以上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) ... 35 件以上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) ... 35 件以上
答え1
keepalive=on
ディレクティブに追加してみてくださいProxyPass
。
グローバル Apache サーバー側でもこれKeepAlive
を設定する必要がある場合があります。on