web-dev-qa-db-ja.com

MongoDBで接続が開かれているSocketTimeout

私はJava MongoDBでいくつかの集約を実行するアプリケーションですが、時々ハングアップしてSocketTimeout例外をスローします。例外の後、アプリは正常に実行されます(少しの間、おそらく例外を再度発生させます)。

たった今発見した この説明 これは考えられる原因のようですが、よくわかりません。

MongoClientを初期化し、DBへの接続を開いたままにします。これが問題になるかどうかはわかりません。データベースを毎回取得し、データベースをガベージコレクション(および接続を閉じる)するだけです。

別のアプローチとして、Mongoに定期的にpingして、接続プールを「最新の状態」に保つことができます。

使用されるクライアントは次のようなものです:

public class DbClient {

    private static MongoClient mongoClient;
    private static MongoDatabase db;

    private DbClient() {}

    public static void init() throws Exception {
        mongoClient = new MongoClient();
    }

    public static MongoDatabase getDB() {
        if(mongoClient == null)
            throw new IllegalStateException("Client not initialized!");

        if(db == null) {
            db = mongoClient.getDatabase("my_db");
        }
        return db;
    }
}

これがSocketTimeoutの考えられる原因ですか?

これはスローされる例外です:

09:20:45.742 [qtp605535417-46] INFO  org.mongodb.driver.connection - Closed connection [connectionId{localValue:16, serverValue:6562}] to myapp.com:27017 because there was a socket exception raised by this connection.
09:20:45.743 [qtp605535417-46] ERROR myapp.service.Api - Error processing request
com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving message
    at com.mongodb.connection.InternalStreamConnection.translateReadException(InternalStreamConnection.Java:474) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.Java:225) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.UsageTrackingInternalConnection.receiveMessage(UsageTrackingInternalConnection.Java:102) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.DefaultConnectionPool$PooledConnection.receiveMessage(DefaultConnectionPool.Java:435) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.Java:112) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.Java:159) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.Java:286) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.Java:173) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.Java:215) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.Java:206) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.Java:112) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.FindOperation$1.call(FindOperation.Java:487) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.FindOperation$1.call(FindOperation.Java:482) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.Java:239) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.Java:212) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.FindOperation.execute(FindOperation.Java:482) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.operation.FindOperation.execute(FindOperation.Java:79) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.Mongo.execute(Mongo.Java:772) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.Mongo$2.execute(Mongo.Java:759) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.OperationIterable.iterator(OperationIterable.Java:47) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.FindIterableImpl.iterator(FindIterableImpl.Java:143) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at myapp.common.db.service.dao.AnalysisMongoImpl.getAnalysis(AnalysisMongoImpl.Java:66) ~[common-0.2.0-SNAPSHOT.jar!/:na]
    at myapp.common.db.service.AnalysisServiceImpl.getAnalysis(AnalysisServiceImpl.Java:31) ~[common-0.2.0-SNAPSHOT.jar!/:na]
    at myapp.aggregator.service.Api$1.handle(Api.Java:88) ~[aggregator-0.2.0-SNAPSHOT.jar!/:na]
    at spark.webserver.MatcherFilter.doFilter(MatcherFilter.Java:139) [spark-core-1.1.1.jar!/:na]
    at spark.webserver.JettyHandler.doHandle(JettyHandler.Java:54) [spark-core-1.1.1.jar!/:na]
    at org.Eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.Java:179) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.Java:136) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.Java:97) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.server.Server.handle(Server.Java:451) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.server.HttpChannel.run(HttpChannel.Java:252) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.Java:266) [jetty-server-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.Java:240) [jetty-io-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.Java:596) [jetty-util-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at org.Eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.Java:527) [jetty-util-9.0.2.v20130417.jar!/:9.0.2.v20130417]
    at Java.lang.Thread.run(Thread.Java:745) [na:1.7.0_95]
Caused by: Java.net.SocketTimeoutException: Read timed out
    at Java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.7.0_95]
    at Java.net.SocketInputStream.read(SocketInputStream.Java:152) ~[na:1.7.0_95]
    at Java.net.SocketInputStream.read(SocketInputStream.Java:122) ~[na:1.7.0_95]
    at com.mongodb.connection.SocketStream.read(SocketStream.Java:85) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.Java:491) ~[mongo-Java-driver-3.2.2.jar!/:na]
    at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.Java:221) ~[mongo-Java-driver-3.2.2.jar!/:na]
    ... 34 common frames omitted
11
Enrichman

何度か試した後、 Azureのロードバランサー の問題であることがわかりました。
60秒間何も操作しないと、保留中のすべての接続が切断されますTCP接続。

さらに掘り下げた後、 MongoDB診断に関するFAQ のこの投稿を見つけ、tcpキープアライブを120秒に設定しました。

Sudo sysctl -w net.ipv4.tcp_keepalive_time=<value>

また、MongoClientの socketKeepAlive をtrueに設定しました。

MongoClientOptions.Builder options = MongoClientOptions.builder();
options.socketKeepAlive(true);
mongoClient = new MongoClient(mongoAddress, options.build());

これらの修正後、問題はなくなったようです!

15
Enrichman

クライアントとサーバー間、またはシャードクラスターのメンバー間でソケットエラーが発生するか、他の合理的な原因がないレプリカセットの場合は、TCPキープアライブ値(たとえば、tcp_keepalive_time Linuxシステムでの値)。一般的なキープアライブ期間は7200秒(2時間)です。ただし、ディストリビューションやmacOSによって設定が異なる場合があります。

MongoDBの場合、キープアライブ期間が短く、120秒(2分)程度の結果が得られます。

Mongodbをインストールした場合は、Linuxでこのコマンドを実行するだけです。

Sudo sysctl -w net.ipv4.tcp_keepalive_time=120

参照: TCPキープアライブ時間がMongoDBのデプロイメントに影響しますか?

1