web-dev-qa-db-fra.com

SocketTimeout avec une connexion ouverte dans MongoDB

J'ai une application Java qui effectue des agrégations sur MongoDB, mais parfois, elle se bloque et génère une exception SocketTimeout. Après l’exception, l’application fonctionnera correctement (pendant un moment, elle relèvera probablement de nouveau l’exception).

Je viens de trouver cette explication cela semble une cause possible mais je ne suis pas sûr.

J'initalise MongoClient et garde la connexion à la base de données ouverte. Je ne sais pas si cela pourrait être un problème et je devrais juste obtenir à chaque fois la base de données et ensuite laisser la base de données être nettoyée (et fermer la connexion).

Une autre approche pourrait consister à envoyer périodiquement un ping à Mongo pour conserver le pool de connexions "frais".

Le client utilisé ressemble à ceci:

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;
    }
}

Est-ce la cause possible de SocketTimeout?

C'est l'exception levée:

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
5
Enrichman

Après quelques essais, j'ai découvert qu'il s'agissait d'un problème lié au Load Balancer d'Azure .
Après 60 secondes d’inactivité, il déconnectera toute connexion en attente TCP.

Après des recherches plus approfondies, j'ai trouvé ce post du diagnostic de MongoDB FAQ , et j'ai défini le maintien de tcp à 120:

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

et j'ai aussi mis le socketKeepAlive du MongoClient sur true:

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

Après ces corrections, le problème semble avoir disparu!

8
Enrichman

Si vous rencontrez des erreurs de socket entre les clients et les serveurs ou entre les membres d'un cluster ou d'un jeu de réplicas partagé sans autre cause raisonnable, vérifiez la valeur TCP keepalive (par exemple, la valeur tcp_keepalive_time sur les systèmes Linux). Une période de Keepalive courante est de 7200 secondes (2 heures); Cependant, différentes distributions et macOS peuvent avoir différents paramètres.

Pour MongoDB, vous obtiendrez de meilleurs résultats avec des périodes de maintien de courte durée, de l’ordre de 120 secondes (deux minutes).

où vous avez installé Mongodb vous devez simplement exécuter cette commande sur Linux

Sudo sysctl -w net.ipv4.tcp_keepalive_time = 120

1
Prashant Agarwal