Mongo db java driver - resource management with client

Background

I have a remote hosting server running a java vm with custom server code for real-time multiplayer game. The server works with matchmaking, rooms, lobby, etc. I am also using Mongo db in the same place where all the questions for the mobile phone quiz are stored.

This is my first attempt at such a project, and although I'm competent in Java, my mongo skill is a beginner at best.

Singleton client

My server contains a static singleton of a mongo client:

     public class ClientSingleton 
  {

  private static ClientSingleton uniqueInstance;
  // The MongoClient class is designed to be thread safe and shared among threads. 
  // We create only 1 instance for our given database cluster and use it across
  // our application.
  private MongoClient mongoClient;
  private MongoClientOptions options;
  private MongoCredential credential;

  private final String password = "xxxxxxxxxxxxxx";
  private final String host = "xx.xx.xx.xx";
  private final int port = 38180;

  /**
    * 
  */
  private ClientSingleton() 
{
    // Setup client credentials for DB connection (user, db name & password)
    credential =  MongoCredential.createCredential("XXXXXX", "DBName", password.toCharArray());
    options = MongoClientOptions.builder()
            .connectTimeout(25000)
            .socketTimeout(60000)
            .connectionsPerHost(100)
            .threadsAllowedToBlockForConnectionMultiplier(5)
            .build();
    try 
    {
        // Create client (server address(host,port), credential, options)
        mongoClient = new MongoClient(new ServerAddress(host, port), 
                Collections.singletonList(credential),
                options);
    } 
    catch (UnknownHostException e) 
    {
        e.printStackTrace();
    }
}

  /**
   * Double checked dispatch method to initialise our client singleton class
   * 
   */
  public static ClientSingleton getInstance()
  {
    if(uniqueInstance == null)
    {
        synchronized (ClientSingleton.class)
        {
            if(uniqueInstance == null)
            {
                uniqueInstance = new ClientSingleton();
            }
        }
    }
    return uniqueInstance;
  }

  /**
   * @return our mongo client
   */
  public MongoClient getClient() {
    return mongoClient;
  }
 }

      

Notes here:

The Mongo client is new to me, and I understand that failing to use the connection pool correctly is one of the main "gotchas" that greatly impact the performance of Mongo db. Also making new connections to db is expensive and I have to try and reuse existing connections. I didn't leave the socket timeout and the default connection timeout (like infinite), if the connection hangs for some reason I think it will get stuck forever! I have set the number of milliseconds that the driver will wait before the connection attempt is aborted, for connections made through the as-server platform (where the server is hosted), a higher timeout is recommended (eg 25 seconds). I also set the number of milliseconds,the driver will wait for a response from the server for all types of requests (requests, records, commands, authentication, etc.). Finally, I set threadAllowedToBlockForConnectionMultiplier to 5 (500) connections, on the FIFO stack, waiting for them to be enabled on the db.

Server zone

The zone receives a game request from the client and receives a metadata string for the quiz type. In this case, "Episode 3". The zone creates space for the user or allows the user to join a room with this property.

Server room

The room then makes a db connection to the mongo collection for the quiz type:

// Get client & collection
mongoDatabase = ClientSingleton.getInstance().getClient().getDB("DBName");
mongoColl = mongoDatabase.getCollection("GOT");

// Query mongo db with meta data string request
queryMetaTags("Episode 3");

      

Notes here:

After the game or should I say that after the downtime in the room the room collapses - that downtime is currently set to 60 minutes. I believe that if the connections to the host are set to 100, then while this room is down it will use up valuable connection resources.

Question

Is this a good way to manage my client connections? If I have several hundred concurrently linked games and each access to the db to pull questions, then maybe after this request free up the client connection for other rooms to use? How to do it? I'm worried about possible bottle necks here!

Mongo Query FYI

    // Query our collection documents metaTag elements for a matching string
// @SuppressWarnings("deprecation")
public void queryMetaTags(String query)
{
    // Query to search all documents in current collection
    List<String> continentList = Arrays.asList(new String[]{query});
    DBObject matchFields = new 
       BasicDBObject("season.questions.questionEntry.metaTags", 
      new BasicDBObject("$in", continentList));
    DBObject groupFields = new BasicDBObject( "_id", "$_id").append("questions", 
       new BasicDBObject("$push","$season.questions"));
    //DBObject unwindshow = new BasicDBObject("$unwind","$show");
    DBObject unwindsea = new BasicDBObject("$unwind", "$season");
    DBObject unwindepi = new BasicDBObject("$unwind", "$season.questions");
    DBObject match = new BasicDBObject("$match", matchFields);
    DBObject group = new BasicDBObject("$group", groupFields); 
    @SuppressWarnings("deprecation")
    AggregationOutput output = 
    mongoColl.aggregate(unwindsea,unwindepi,match,group);

    String jsonString = null;
    JSONObject jsonObject = null;
    JSONArray jsonArray = null;
    ArrayList<JSONObject> ourResultsArray = new ArrayList<JSONObject>();

    // Loop for each document in our collection
    for (DBObject result : output.results()) 
    {       
        try 
        {
            // Parse our results so we can add them to an ArrayList
            jsonString = JSON.serialize(result);             
            jsonObject = new JSONObject(jsonString);
            jsonArray = jsonObject.getJSONArray("questions");

            for (int i = 0; i < jsonArray.length(); i++)
            {
                // Put each of our returned questionEntry elements into an ArrayList
                ourResultsArray.add(jsonArray.getJSONObject(i));
            }                
        } 
        catch (JSONException e1) 
        {
            e1.printStackTrace();
        }
    }   
    pullOut10Questions(ourResultsArray);
}

      

+3


source to share


1 answer


The way I did it was to use Spring to create MongoClient Bean. Then you can auto-install this bean wherever needed.

For example:

MongoConfig.java

import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.tescobank.insurance.telematics.data.connector.config.DatabaseProperties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.UnknownHostException;

@Configuration
public class MongoConfig {

    private @Autowired DatabaseProperties properties;

    @Bean
    public MongoClient fooClient() throws UnknownHostException {
        return mongo(properties.getFooDatabaseURI());
    }

}

      



Class requiring Mongodb connection:

@Component
public class DatabaseUser {

    private MongoClient mongoClient;

    ....

    @Autowired
    public DatabaseUser(MongoClient mongoClient) {
         this.mongoClient = mongoClient;
    }
}

      

Spring will then create the connection and route it where needed. What you have done seems to be very complex and is perhaps trying to recreate the functionality you get for free using a tried and tested framework like Spring. I've tried to avoid using Singletons altogether if I could avoid it. I had no performance issues using Mongodb connections like this.

+1


source







All Articles